@ts-cloud/core 0.16.50 → 0.16.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,26 +1,26 @@
1
- import{createRequire as Bs}from"node:module";var Ms=Object.defineProperty;var Ls=(e)=>e;function Os(e,t){this[e]=Ls.bind(null,t)}var Oe=(e,t)=>{for(var n in t)Ms(e,n,{get:t[n],enumerable:!0,configurable:!0,set:Os.bind(t,n)})};var $s=(e,t,n)=>()=>{if(e)try{t=e(e=0)}catch(r){n=[r]}if(n)throw n[0];return t};var Fs=Bs(import.meta.url);function _r(e){let t=typeof e==="string"?new URL(e):e,{hostname:n,pathname:r}=t;if(n.endsWith(".on.aws")){let o=n.match(/^[^.]+\.lambda-url\.([^.]+)\.on\.aws$/);if(o)return{service:"lambda",region:o[1]};return{service:"",region:""}}if(n.endsWith(".r2.cloudflarestorage.com"))return{service:"s3",region:"auto"};if(n.endsWith(".backblazeb2.com")){let o=n.match(/^(?:[^.]+\.)?s3\.([^.]+)\.backblazeb2\.com$/);if(o)return{service:"s3",region:o[1]};return{service:"",region:""}}let i=n.replace("dualstack.","").match(/([^.]+)\.(?:([^.]+)\.)?amazonaws\.com(?:\.cn)?$/);if(!i)return{service:"",region:""};let s=i[1],a=i[2]||"";if(a==="us-gov")a="us-gov-west-1";else if(a==="s3"||a==="s3-accelerate")a="us-east-1",s="s3";else if(s==="iot")if(n.startsWith("iot."))s="execute-api";else if(n.startsWith("data.jobs.iot."))s="iot-jobs-data";else s=r==="/mqtt"?"iotdevicegateway":"iotdata";else if(s==="autoscaling");else if(!a&&s.startsWith("s3-"))a=s.slice(3).replace(/^fips-|^external-1/,""),s="s3";else if(s.endsWith("-fips"))s=s.slice(0,-5);else if(a&&/-\d$/.test(s)&&!/-\d$/.test(a))[s,a]=[a,s];return s=So[s]||s,{service:s,region:a||"us-east-1"}}function V(e){let{method:t,url:n,body:r="",accessKeyId:i,secretAccessKey:s,sessionToken:a,signQuery:o=!1,expiresIn:c=86400,datetime:l}=e,u=new URL(n),m=u.hostname,p=_r(u),g=e.service||p.service,y=e.region||p.region;if(!g)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!y)throw Error("Could not detect region from URL. Please provide region explicitly.");let h=l||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),b=h.substring(0,8),v=[b,y,g,"aws4_request"].join("/"),T="AWS4-HMAC-SHA256";if(o)return Ao({urlObj:u,method:t,body:r,accessKeyId:i,secretAccessKey:s,sessionToken:a,service:g,region:y,timestamp:h,date:b,credentialScope:v,algorithm:T,expiresIn:c,cache:e.cache});let A=u.pathname||"/",R=Pt(u.searchParams),P={host:m,"x-amz-date":h,...e.headers};if(a)P["x-amz-security-token"]=a;let E=Object.keys(P).some((Pe)=>Pe.toLowerCase()==="content-type");if(r&&!E)P["content-type"]="application/x-amz-json-1.0";if(g==="s3"&&!P["x-amz-content-sha256"])P["x-amz-content-sha256"]=st(r);let w=Ur(P),I=Hr(P),D=P["x-amz-content-sha256"]||st(r),k=[t,Et(A),R,w,I,D].join(`
2
- `),O=st(k),j=[T,h,v,O].join(`
3
- `),K=e.cache??We,re=Kr(s,b,y,g,j,K),U=[`${T} Credential=${i}/${v}`,`SignedHeaders=${I}`,`Signature=${re}`].join(", ");return P.authorization=U,{url:n,method:t,headers:P,body:r||void 0}}async function Wr(e){let{method:t,url:n,body:r="",accessKeyId:i,secretAccessKey:s,sessionToken:a,signQuery:o=!1,expiresIn:c=86400,datetime:l}=e,u=new URL(n),m=u.hostname,p=_r(u),g=e.service||p.service,y=e.region||p.region;if(!g)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!y)throw Error("Could not detect region from URL. Please provide region explicitly.");let h=l||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),b=h.substring(0,8),v=[b,y,g,"aws4_request"].join("/"),T="AWS4-HMAC-SHA256";if(o)return Co({urlObj:u,method:t,body:r,accessKeyId:i,secretAccessKey:s,sessionToken:a,service:g,region:y,timestamp:h,date:b,credentialScope:v,algorithm:T,expiresIn:c,cache:e.cache});let A=u.pathname||"/",R=Pt(u.searchParams),P={host:m,"x-amz-date":h,...e.headers};if(a)P["x-amz-security-token"]=a;let E=Object.keys(P).some((qe)=>qe.toLowerCase()==="content-type");if(r&&!E)P["content-type"]="application/x-amz-json-1.0";let w=await vt(r);if(g==="s3"&&!P["x-amz-content-sha256"])P["x-amz-content-sha256"]=w;let I=Ur(P),D=Hr(P),k=P["x-amz-content-sha256"]||w,O=[t,Et(A),R,I,D,k].join(`
4
- `),j=await vt(O),K=[T,h,v,j].join(`
5
- `),re=e.cache??We,U=await qr(s,b,y,g,K,re),Pe=[`${T} Credential=${i}/${v}`,`SignedHeaders=${D}`,`Signature=${U}`].join(", ");return P.authorization=Pe,{url:n,method:t,headers:P,body:r||void 0}}function Ao(e){let{urlObj:t,method:n,body:r,accessKeyId:i,secretAccessKey:s,sessionToken:a,service:o,region:c,timestamp:l,date:u,credentialScope:m,algorithm:p,expiresIn:g,cache:y}=e,h=new URL(t.toString());h.searchParams.set("X-Amz-Algorithm",p),h.searchParams.set("X-Amz-Credential",`${i}/${m}`),h.searchParams.set("X-Amz-Date",l),h.searchParams.set("X-Amz-Expires",String(g));let b=o==="s3"?"UNSIGNED-PAYLOAD":st(r);if(o==="s3")h.searchParams.set("X-Amz-Content-Sha256",b);let v="host";if(h.searchParams.set("X-Amz-SignedHeaders",v),a)h.searchParams.set("X-Amz-Security-Token",a);let T=Et(h.pathname||"/"),A=`host:${h.hostname}
6
- `,R=Pt(h.searchParams),P=[n,T,R,A,v,b].join(`
7
- `),E=[p,l,m,st(P)].join(`
8
- `),I=Kr(s,u,c,o,E,y??We);return h.searchParams.set("X-Amz-Signature",I),{url:h.toString(),method:n,headers:{},body:r||void 0}}async function Co(e){let{urlObj:t,method:n,body:r,accessKeyId:i,secretAccessKey:s,sessionToken:a,service:o,region:c,timestamp:l,date:u,credentialScope:m,algorithm:p,expiresIn:g,cache:y}=e,h=new URL(t.toString());h.searchParams.set("X-Amz-Algorithm",p),h.searchParams.set("X-Amz-Credential",`${i}/${m}`),h.searchParams.set("X-Amz-Date",l),h.searchParams.set("X-Amz-Expires",String(g));let b=o==="s3"?"UNSIGNED-PAYLOAD":await vt(r);if(o==="s3")h.searchParams.set("X-Amz-Content-Sha256",b);let v="host";if(h.searchParams.set("X-Amz-SignedHeaders",v),a)h.searchParams.set("X-Amz-Security-Token",a);let T=Et(h.pathname||"/"),A=`host:${h.hostname}
9
- `,R=Pt(h.searchParams),P=[n,T,R,A,v,b].join(`
10
- `),E=[p,l,m,await vt(P)].join(`
11
- `),I=await qr(s,u,c,o,E,y??We);return h.searchParams.set("X-Amz-Signature",I),{url:h.toString(),method:n,headers:{},body:r||void 0}}function Vr(e){let{url:t,method:n="GET",expiresIn:r=3600,...i}=e,s=Math.min(r,604800);return V({...i,url:t,method:n,signQuery:!0,expiresIn:s}).url}async function Qg(e){let{url:t,method:n="GET",expiresIn:r=3600,...i}=e,s=Math.min(r,604800);return(await Wr({...i,url:t,method:n,signQuery:!0,expiresIn:s})).url}function Ur(e){return Object.keys(e).sort().map((t)=>`${t.toLowerCase()}:${e[t].trim().replace(/\s+/g," ")}`).join(`
1
+ import{createRequire as Bs}from"node:module";var Ms=Object.defineProperty;var Ls=(e)=>e;function Os(e,t){this[e]=Ls.bind(null,t)}var Be=(e,t)=>{for(var n in t)Ms(e,n,{get:t[n],enumerable:!0,configurable:!0,set:Os.bind(t,n)})};var $s=(e,t,n)=>()=>{if(e)try{t=e(e=0)}catch(r){n=[r]}if(n)throw n[0];return t};var Fs=Bs(import.meta.url);function _r(e){let t=typeof e==="string"?new URL(e):e,{hostname:n,pathname:r}=t;if(n.endsWith(".on.aws")){let o=n.match(/^[^.]+\.lambda-url\.([^.]+)\.on\.aws$/);if(o)return{service:"lambda",region:o[1]};return{service:"",region:""}}if(n.endsWith(".r2.cloudflarestorage.com"))return{service:"s3",region:"auto"};if(n.endsWith(".backblazeb2.com")){let o=n.match(/^(?:[^.]+\.)?s3\.([^.]+)\.backblazeb2\.com$/);if(o)return{service:"s3",region:o[1]};return{service:"",region:""}}let i=n.replace("dualstack.","").match(/([^.]+)\.(?:([^.]+)\.)?amazonaws\.com(?:\.cn)?$/);if(!i)return{service:"",region:""};let s=i[1],a=i[2]||"";if(a==="us-gov")a="us-gov-west-1";else if(a==="s3"||a==="s3-accelerate")a="us-east-1",s="s3";else if(s==="iot")if(n.startsWith("iot."))s="execute-api";else if(n.startsWith("data.jobs.iot."))s="iot-jobs-data";else s=r==="/mqtt"?"iotdevicegateway":"iotdata";else if(s==="autoscaling");else if(!a&&s.startsWith("s3-"))a=s.slice(3).replace(/^fips-|^external-1/,""),s="s3";else if(s.endsWith("-fips"))s=s.slice(0,-5);else if(a&&/-\d$/.test(s)&&!/-\d$/.test(a))[s,a]=[a,s];return s=So[s]||s,{service:s,region:a||"us-east-1"}}function H(e){let{method:t,url:n,body:r="",accessKeyId:i,secretAccessKey:s,sessionToken:a,signQuery:o=!1,expiresIn:c=86400,datetime:l}=e,u=new URL(n),m=u.hostname,p=_r(u),g=e.service||p.service,y=e.region||p.region;if(!g)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!y)throw Error("Could not detect region from URL. Please provide region explicitly.");let h=l||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),b=h.substring(0,8),C=[b,y,g,"aws4_request"].join("/"),T="AWS4-HMAC-SHA256";if(o)return Ao({urlObj:u,method:t,body:r,accessKeyId:i,secretAccessKey:s,sessionToken:a,service:g,region:y,timestamp:h,date:b,credentialScope:C,algorithm:T,expiresIn:c,cache:e.cache});let A=u.pathname||"/",R=Et(u.searchParams),P={host:m,"x-amz-date":h,...e.headers};if(a)P["x-amz-security-token"]=a;let E=Object.keys(P).some((K)=>K.toLowerCase()==="content-type");if(r&&!E)P["content-type"]="application/x-amz-json-1.0";if(g==="s3"&&!P["x-amz-content-sha256"])P["x-amz-content-sha256"]=at(r);let w=Ur(P),I=Hr(P),D=P["x-amz-content-sha256"]||at(r),k=[t,wt(A),R,w,I,D].join(`
2
+ `),O=at(k),ne=[T,h,C,O].join(`
3
+ `),_=e.cache??Ue,q=Kr(s,b,y,g,ne,_),F=[`${T} Credential=${i}/${C}`,`SignedHeaders=${I}`,`Signature=${q}`].join(", ");return P.authorization=F,{url:n,method:t,headers:P,body:r||void 0}}async function Wr(e){let{method:t,url:n,body:r="",accessKeyId:i,secretAccessKey:s,sessionToken:a,signQuery:o=!1,expiresIn:c=86400,datetime:l}=e,u=new URL(n),m=u.hostname,p=_r(u),g=e.service||p.service,y=e.region||p.region;if(!g)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!y)throw Error("Could not detect region from URL. Please provide region explicitly.");let h=l||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),b=h.substring(0,8),C=[b,y,g,"aws4_request"].join("/"),T="AWS4-HMAC-SHA256";if(o)return Co({urlObj:u,method:t,body:r,accessKeyId:i,secretAccessKey:s,sessionToken:a,service:g,region:y,timestamp:h,date:b,credentialScope:C,algorithm:T,expiresIn:c,cache:e.cache});let A=u.pathname||"/",R=Et(u.searchParams),P={host:m,"x-amz-date":h,...e.headers};if(a)P["x-amz-security-token"]=a;let E=Object.keys(P).some((de)=>de.toLowerCase()==="content-type");if(r&&!E)P["content-type"]="application/x-amz-json-1.0";let w=await Tt(r);if(g==="s3"&&!P["x-amz-content-sha256"])P["x-amz-content-sha256"]=w;let I=Ur(P),D=Hr(P),k=P["x-amz-content-sha256"]||w,O=[t,wt(A),R,I,D,k].join(`
4
+ `),ne=await Tt(O),_=[T,h,C,ne].join(`
5
+ `),q=e.cache??Ue,F=await qr(s,b,y,g,_,q),K=[`${T} Credential=${i}/${C}`,`SignedHeaders=${D}`,`Signature=${F}`].join(", ");return P.authorization=K,{url:n,method:t,headers:P,body:r||void 0}}function Ao(e){let{urlObj:t,method:n,body:r,accessKeyId:i,secretAccessKey:s,sessionToken:a,service:o,region:c,timestamp:l,date:u,credentialScope:m,algorithm:p,expiresIn:g,cache:y}=e,h=new URL(t.toString());h.searchParams.set("X-Amz-Algorithm",p),h.searchParams.set("X-Amz-Credential",`${i}/${m}`),h.searchParams.set("X-Amz-Date",l),h.searchParams.set("X-Amz-Expires",String(g));let b=o==="s3"?"UNSIGNED-PAYLOAD":at(r);if(o==="s3")h.searchParams.set("X-Amz-Content-Sha256",b);let C="host";if(h.searchParams.set("X-Amz-SignedHeaders",C),a)h.searchParams.set("X-Amz-Security-Token",a);let T=wt(h.pathname||"/"),A=`host:${h.hostname}
6
+ `,R=Et(h.searchParams),P=[n,T,R,A,C,b].join(`
7
+ `),E=[p,l,m,at(P)].join(`
8
+ `),I=Kr(s,u,c,o,E,y??Ue);return h.searchParams.set("X-Amz-Signature",I),{url:h.toString(),method:n,headers:{},body:r||void 0}}async function Co(e){let{urlObj:t,method:n,body:r,accessKeyId:i,secretAccessKey:s,sessionToken:a,service:o,region:c,timestamp:l,date:u,credentialScope:m,algorithm:p,expiresIn:g,cache:y}=e,h=new URL(t.toString());h.searchParams.set("X-Amz-Algorithm",p),h.searchParams.set("X-Amz-Credential",`${i}/${m}`),h.searchParams.set("X-Amz-Date",l),h.searchParams.set("X-Amz-Expires",String(g));let b=o==="s3"?"UNSIGNED-PAYLOAD":await Tt(r);if(o==="s3")h.searchParams.set("X-Amz-Content-Sha256",b);let C="host";if(h.searchParams.set("X-Amz-SignedHeaders",C),a)h.searchParams.set("X-Amz-Security-Token",a);let T=wt(h.pathname||"/"),A=`host:${h.hostname}
9
+ `,R=Et(h.searchParams),P=[n,T,R,A,C,b].join(`
10
+ `),E=[p,l,m,await Tt(P)].join(`
11
+ `),I=await qr(s,u,c,o,E,y??Ue);return h.searchParams.set("X-Amz-Signature",I),{url:h.toString(),method:n,headers:{},body:r||void 0}}function Vr(e){let{url:t,method:n="GET",expiresIn:r=3600,...i}=e,s=Math.min(r,604800);return H({...i,url:t,method:n,signQuery:!0,expiresIn:s}).url}async function Qg(e){let{url:t,method:n="GET",expiresIn:r=3600,...i}=e,s=Math.min(r,604800);return(await Wr({...i,url:t,method:n,signQuery:!0,expiresIn:s})).url}function Ur(e){return Object.keys(e).sort().map((t)=>`${t.toLowerCase()}:${e[t].trim().replace(/\s+/g," ")}`).join(`
12
12
  `)+`
13
- `}function Hr(e){return Object.keys(e).sort().map((t)=>t.toLowerCase()).join(";")}function Pt(e){let t=[];return e.forEach((n,r)=>{t.push([Xt(r),Xt(n)])}),t.sort((n,r)=>{if(n[0]<r[0])return-1;if(n[0]>r[0])return 1;if(n[1]<r[1])return-1;if(n[1]>r[1])return 1;return 0}),t.map(([n,r])=>`${n}=${r}`).join("&")}function Et(e){return e.split("/").map((t)=>Xt(t)).join("/")}function Xt(e){return encodeURIComponent(e).replace(/[!'()*]/g,(t)=>`%${t.charCodeAt(0).toString(16).toUpperCase()}`)}function st(e){if(!_e)throw Error("Synchronous hash not available in browser. Use signRequestAsync() instead.");return _e.createHash("sha256").update(e,"utf8").digest("hex")}function rt(e,t){if(!_e)throw Error("Synchronous hmac not available in browser. Use signRequestAsync() instead.");return _e.createHmac("sha256",e).update(t,"utf8").digest()}async function vt(e){let n=new TextEncoder().encode(e),r=await crypto.subtle.digest("SHA-256",n);return jr(new Uint8Array(r))}async function it(e,t){let n=new TextEncoder,r=typeof e==="string"?n.encode(e):e,i=n.encode(t),s=await crypto.subtle.importKey("raw",r.buffer,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),a=await crypto.subtle.sign("HMAC",s,i.buffer);return new Uint8Array(a)}function jr(e){return Array.from(e).map((t)=>t.toString(16).padStart(2,"0")).join("")}function Kr(e,t,n,r,i,s){let a=`${e}:${t}:${n}:${r}`,o=s.get(a);if(!o){let c=rt(`AWS4${e}`,t),l=rt(c,n),u=rt(l,r);if(o=rt(u,"aws4_request"),s.size>=Gr){let m=s.keys().next().value;if(m)s.delete(m)}s.set(a,o)}return rt(o,i).toString("hex")}async function qr(e,t,n,r,i,s){let a=`${e}:${t}:${n}:${r}`,o=s.get(a);if(!o){let l=await it(`AWS4${e}`,t),u=await it(l,n),m=await it(u,r);if(o=await it(m,"aws4_request"),s.size>=Gr){let p=s.keys().next().value;if(p)s.delete(p)}s.set(a,o)}let c=await it(o,i);return jr(c)}function zr(e,t){return t.includes(e)}function Tt(e,t,n){let r=t*Math.pow(2,e),i=Math.random()*0.3*r;return Math.min(r+i,n)}function Rt(e){return new Promise((t)=>setTimeout(t,e))}async function De(e,t){let{maxRetries:n=3,initialDelayMs:r=100,maxDelayMs:i=5000,retryableStatusCodes:s=[429,500,502,503,504],timeoutMs:a=30000}=t??{},o,c;for(let l=0;l<=n;l++){let u=V(e),m={method:u.method,headers:u.headers};if(u.body)m.body=u.body;let p=new AbortController,g=setTimeout(()=>p.abort(),a);m.signal=p.signal;try{let y=await fetch(u.url,m);if(clearTimeout(g),c=y,y.ok)return y;if(l<n&&zr(y.status,s)){let b=Tt(l,r,i);await Rt(b);continue}let h=await y.text();throw Error(`AWS API request failed (${y.status}): ${h}`)}catch(y){if(clearTimeout(g),o=y,y instanceof Error&&y.name==="AbortError")o=Error(`Request timed out after ${a}ms`);if(l<n&&!(y instanceof Error&&y.message.includes("AWS API request failed"))){let h=Tt(l,r,i);await Rt(h);continue}throw o}}throw o??Error("Request failed after retries")}async function Jg(e){return De(e,{maxRetries:0})}async function Yg(e,t){let{maxRetries:n=3,initialDelayMs:r=100,maxDelayMs:i=5000,retryableStatusCodes:s=[429,500,502,503,504],timeoutMs:a=30000}=t??{},o;for(let c=0;c<=n;c++){let l=await Wr(e),u={method:l.method,headers:l.headers};if(l.body)u.body=l.body;let m=new AbortController,p=setTimeout(()=>m.abort(),a);u.signal=m.signal;try{let g=await fetch(l.url,u);if(clearTimeout(p),g.ok)return g;if(c<n&&zr(g.status,s)){let h=Tt(c,r,i);await Rt(h);continue}let y=await g.text();throw Error(`AWS API request failed (${g.status}): ${y}`)}catch(g){if(clearTimeout(p),o=g,g instanceof Error&&g.name==="AbortError")o=Error(`Request timed out after ${a}ms`);if(c<n&&!(g instanceof Error&&g.message.includes("AWS API request failed"))){let y=Tt(c,r,i);await Rt(y);continue}throw o}}throw o??Error("Request failed after retries")}async function wt(e){let t=await e.text(),n={},r=/<(\w+)>([^<]+)<\/\1>/g,i;while((i=r.exec(t))!==null){let[,s,a]=i;n[s]=a}return n}async function Zg(e){return await e.json()}function Xg(){We.clear()}function ey(){return We.size}function ty(){return _e!==void 0}function ny(){return typeof crypto<"u"&&typeof crypto.subtle<"u"}var _e,We,Gr=100,So;var Ve=$s(async()=>{try{_e=await import("node:crypto")}catch{}We=new Map,So={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"}});var ur={};Oe(ur,{default:()=>ba,handler:()=>jt});var yr={};Oe(yr,{default:()=>Sa,handler:()=>Kt});var Hi={};Oe(Hi,{EmailAnalyticsModule:()=>pt,EmailRules:()=>Mn,EmailScheduling:()=>xn,EmailSearch:()=>Dn,EmailTemplates:()=>ke,EmailThreading:()=>Nn,SharedMailboxes:()=>kn});var ji={};Oe(ji,{default:()=>Hc,handler:()=>Uc});var Ki={};Oe(Ki,{CallAnalytics:()=>On,CallRecording:()=>Ln,Callbacks:()=>xt,IVRBuilder:()=>He});var qi={};Oe(qi,{AbTesting:()=>Te,LinkTracking:()=>_n,MmsSupport:()=>Fn,SmsAnalytics:()=>Bn,SmsCampaigns:()=>$n,SmsChatbot:()=>Gn});var au={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}},ou={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}}}};import{isAbsolute as Gt,join as gt,relative as Gs}from"node:path";var _t=".ts-cloud",Qn="TS_CLOUD_STATE_DIR",Wt=null;function uu(e){Wt=e?.trim()||null}function du(){return Boolean(process.env[Qn]?.trim()||Wt)}function $e(){return process.env[Qn]?.trim()||Wt||_t}function Jn(...e){return gt($e(),...e)}function _s(e,...t){let n=$e();return Gt(n)?gt(n,...t):gt(e,n,...t)}function mu(e,t=process.cwd()){let n=(i,s)=>{let a=Gs(i,s);return a===""||!a.startsWith("..")&&!Gt(a)},r=Gt(e)?e:gt(t,e);return n(_s(t),r)}function Yn(e){let t=e.infrastructure?.compute!=null,n=Object.values(e.environments??{}).some((r)=>r?.app!=null);return{server:t,serverless:n}}function gu(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:t}=Yn(e);return t?"serverless":"server"}function yu(e){let{server:t,serverless:n}=Yn(e);if(t&&n)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(e.mode==="server"&&n&&!t)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&t&&!n)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function hu(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function Ws(e){return typeof e==="object"&&e!==null?e:{}}function Vs(e){return e===!0||typeof e==="object"&&e!==null}function Us(e,t){let n=t?e.environments?.[t]:void 0;if(n?.domain)return n.domain;let r=Object.values(e.sites??{}),i=e.sites?.main?.domain??r.find((s)=>s.domain)?.domain;if(i)return i;return`${e.project?.slug??"app"}.local`}function Hs(e){let t=e.indexOf(".");return t>0?e.slice(t+1):void 0}function js(e,t={}){let n=e.infrastructure?.compute?.managedServices?.mail,r=Ws(n),i=t.environmentType??(t.environment?e.environments?.[t.environment]?.type:void 0),s=r.mode??(i==="production"?"server":"catcher"),a=s==="server",o=Us(e,t.environment),c=r.hostname??(a?`mail.${o}`:"localhost"),l=r.ports??{},u=a?{smtp:l.smtp??25,submission:l.submission??587,submissions:l.submissions??465,imap:l.imap??143,imaps:l.imaps??993,webmail:l.webmail??8080,managesieve:l.managesieve}:{smtp:l.smtp??1025,submission:l.submission,submissions:l.submissions,imap:l.imap,imaps:l.imaps,webmail:l.webmail??8025,managesieve:l.managesieve},m=r.tls??{},p=m.enabled??a,g=!!(m.certPath&&m.keyPath),y=(r.accounts??[]).map((j)=>({address:j.address,password:j.password,passwordPolicy:j.passwordPolicy??"initial"})),h=typeof r.dkim==="object"&&r.dkim!==null?r.dkim:{},b=r.dkim===!1?!1:r.dkim===!0||a,v=typeof r.webmail==="object"&&r.webmail!==null?r.webmail:{},T=r.webmail===!1?!1:v.enabled??!0,A=c.includes(".")&&!c.endsWith(".local")&&!/^\d+\.\d+\.\d+\.\d+$/.test(c),R=v.domain===!1?void 0:v.domain??(a&&A?c:void 0),P=v.tls??(R?!1:p),E=[...new Set(v.aliases??[])].filter((j)=>j!==R),w=r.spam??{},I=r.delivery??(a?"direct":"none"),D=r.expose??a,k=Hs(c),O=[...new Set([c,...k?[k]:[],...r.domains??[]])];return{enabled:Vs(n),mode:s,version:r.version,hostname:c,domains:O,ports:u,tls:{enabled:p,acme:p&&!g&&(m.acme??!0),certPath:m.certPath,keyPath:m.keyPath,requireForAuth:m.requireForAuth??(p&&a),acmeEmail:m.acmeEmail??y[0]?.address},dkim:{enabled:b,selector:h.selector??"default",rotate:h.rotate??!1,rotateIntervalDays:h.rotateIntervalDays??90},webmail:{enabled:T,port:v.port??u.webmail,domain:R,aliases:E,tls:P,secureCookies:v.secureCookies??(!!R||P)},delivery:I,sesRegion:r.sesRegion??"us-east-1",accounts:y,storagePath:r.storagePath??"/var/lib/mail",maxMessageSize:r.maxMessageSize??26214400,spam:{enabled:w.enabled??a,enforce:w.enforce??!1,junkScore:w.junkScore??5,rejectScore:w.rejectScore??12,dnsbl:w.dnsbl??a,greylist:w.greylist??!1},webhookUrl:r.webhookUrl,expose:D,bindAddress:D?"0.0.0.0":"127.0.0.1"}}function Su(e){if(!e.enabled||!e.expose)return[];let t=[e.ports.smtp,e.ports.submission,e.ports.submissions,e.ports.imap,e.ports.imaps,e.ports.managesieve].filter((n)=>typeof n==="number");if(e.webmail.enabled&&!e.webmail.domain)t.push(e.webmail.port);return[...new Set(t)].sort((n,r)=>n-r)}function Au(e){if(!e.enabled)return{};let t=e.ports.submission??e.ports.smtp,n={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(t)};if(e.mode==="server"){n.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let r=e.accounts[0];if(r)n.MAIL_USERNAME=r.address,n.MAIL_PASSWORD=r.password}else n.MAIL_ENCRYPTION="null",n.MAIL_USERNAME="null",n.MAIL_PASSWORD="null";return n}function Cu(e){if(!e.enabled||!e.webmail.enabled||!e.webmail.domain)return{};let t=[e.webmail.domain,...e.webmail.aliases];if(!Number.isInteger(e.webmail.port)||e.webmail.port<1||e.webmail.port>65535)throw Error("Mail webmail port must be between 1 and 65535");return Object.fromEntries(t.map((n,r)=>{if(!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(n))throw Error(`Invalid mail webmail hostname: ${n}`);return[`__mail_webmail_${r}`,{domain:n,proxyTo:`localhost:${e.webmail.port}`}]}))}function vu(e,t={}){let n=e.infrastructure?.compute?.proxy,r=js(e,t);if(!r.enabled||!r.webmail.enabled||!r.webmail.domain)return n;return{engine:"rpx",onDemandTls:!0,onDemandTlsEmail:r.tls.acmeEmail??`webmaster@${r.webmail.domain}`,...n}}function Ru(e){if(e.cloud?.provider)return e.cloud.provider;if(e.ssh?.hosts?.length)return"ssh";if(e.hetzner?.apiToken)return"hetzner";return"aws"}class Ks{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,t){return this.template.Resources[e]=t,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,t){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=t,this}addOutput(e,t){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=t,this}addMetadata(e,t){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[e]=t,this}hasResource(e){return e in this.template.Resources}getResources(){return this.template.Resources}build(){return this.template}toJSON(e=!0){return JSON.stringify(this.template,null,e?2:0)}toYAML(){return this.convertToYAML(this.template)}convertToYAML(e,t=0){let n=" ".repeat(t),r="";for(let[i,s]of Object.entries(e)){if(s===null||s===void 0)continue;if(typeof s==="object"&&!Array.isArray(s))r+=`${n}${i}:
13
+ `}function Hr(e){return Object.keys(e).sort().map((t)=>t.toLowerCase()).join(";")}function Et(e){let t=[];return e.forEach((n,r)=>{t.push([Xt(r),Xt(n)])}),t.sort((n,r)=>{if(n[0]<r[0])return-1;if(n[0]>r[0])return 1;if(n[1]<r[1])return-1;if(n[1]>r[1])return 1;return 0}),t.map(([n,r])=>`${n}=${r}`).join("&")}function wt(e){return e.split("/").map((t)=>Xt(t)).join("/")}function Xt(e){return encodeURIComponent(e).replace(/[!'()*]/g,(t)=>`%${t.charCodeAt(0).toString(16).toUpperCase()}`)}function at(e){if(!Ve)throw Error("Synchronous hash not available in browser. Use signRequestAsync() instead.");return Ve.createHash("sha256").update(e,"utf8").digest("hex")}function it(e,t){if(!Ve)throw Error("Synchronous hmac not available in browser. Use signRequestAsync() instead.");return Ve.createHmac("sha256",e).update(t,"utf8").digest()}async function Tt(e){let n=new TextEncoder().encode(e),r=await crypto.subtle.digest("SHA-256",n);return jr(new Uint8Array(r))}async function st(e,t){let n=new TextEncoder,r=typeof e==="string"?n.encode(e):e,i=n.encode(t),s=await crypto.subtle.importKey("raw",r.buffer,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),a=await crypto.subtle.sign("HMAC",s,i.buffer);return new Uint8Array(a)}function jr(e){return Array.from(e).map((t)=>t.toString(16).padStart(2,"0")).join("")}function Kr(e,t,n,r,i,s){let a=`${e}:${t}:${n}:${r}`,o=s.get(a);if(!o){let c=it(`AWS4${e}`,t),l=it(c,n),u=it(l,r);if(o=it(u,"aws4_request"),s.size>=Gr){let m=s.keys().next().value;if(m)s.delete(m)}s.set(a,o)}return it(o,i).toString("hex")}async function qr(e,t,n,r,i,s){let a=`${e}:${t}:${n}:${r}`,o=s.get(a);if(!o){let l=await st(`AWS4${e}`,t),u=await st(l,n),m=await st(u,r);if(o=await st(m,"aws4_request"),s.size>=Gr){let p=s.keys().next().value;if(p)s.delete(p)}s.set(a,o)}let c=await st(o,i);return jr(c)}function zr(e,t){return t.includes(e)}function Rt(e,t,n){let r=t*Math.pow(2,e),i=Math.random()*0.3*r;return Math.min(r+i,n)}function Pt(e){return new Promise((t)=>setTimeout(t,e))}async function Ne(e,t){let{maxRetries:n=3,initialDelayMs:r=100,maxDelayMs:i=5000,retryableStatusCodes:s=[429,500,502,503,504],timeoutMs:a=30000}=t??{},o,c;for(let l=0;l<=n;l++){let u=H(e),m={method:u.method,headers:u.headers};if(u.body)m.body=u.body;let p=new AbortController,g=setTimeout(()=>p.abort(),a);m.signal=p.signal;try{let y=await fetch(u.url,m);if(clearTimeout(g),c=y,y.ok)return y;if(l<n&&zr(y.status,s)){let b=Rt(l,r,i);await Pt(b);continue}let h=await y.text();throw Error(`AWS API request failed (${y.status}): ${h}`)}catch(y){if(clearTimeout(g),o=y,y instanceof Error&&y.name==="AbortError")o=Error(`Request timed out after ${a}ms`);if(l<n&&!(y instanceof Error&&y.message.includes("AWS API request failed"))){let h=Rt(l,r,i);await Pt(h);continue}throw o}}throw o??Error("Request failed after retries")}async function Jg(e){return Ne(e,{maxRetries:0})}async function Yg(e,t){let{maxRetries:n=3,initialDelayMs:r=100,maxDelayMs:i=5000,retryableStatusCodes:s=[429,500,502,503,504],timeoutMs:a=30000}=t??{},o;for(let c=0;c<=n;c++){let l=await Wr(e),u={method:l.method,headers:l.headers};if(l.body)u.body=l.body;let m=new AbortController,p=setTimeout(()=>m.abort(),a);u.signal=m.signal;try{let g=await fetch(l.url,u);if(clearTimeout(p),g.ok)return g;if(c<n&&zr(g.status,s)){let h=Rt(c,r,i);await Pt(h);continue}let y=await g.text();throw Error(`AWS API request failed (${g.status}): ${y}`)}catch(g){if(clearTimeout(p),o=g,g instanceof Error&&g.name==="AbortError")o=Error(`Request timed out after ${a}ms`);if(c<n&&!(g instanceof Error&&g.message.includes("AWS API request failed"))){let y=Rt(c,r,i);await Pt(y);continue}throw o}}throw o??Error("Request failed after retries")}async function It(e){let t=await e.text(),n={},r=/<(\w+)>([^<]+)<\/\1>/g,i;while((i=r.exec(t))!==null){let[,s,a]=i;n[s]=a}return n}async function Zg(e){return await e.json()}function Xg(){Ue.clear()}function ey(){return Ue.size}function ty(){return Ve!==void 0}function ny(){return typeof crypto<"u"&&typeof crypto.subtle<"u"}var Ve,Ue,Gr=100,So;var He=$s(async()=>{try{Ve=await import("node:crypto")}catch{}Ue=new Map,So={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"}});var ur={};Be(ur,{default:()=>ba,handler:()=>jt});var yr={};Be(yr,{default:()=>Sa,handler:()=>Kt});var Hi={};Be(Hi,{EmailAnalyticsModule:()=>gt,EmailRules:()=>Mn,EmailScheduling:()=>xn,EmailSearch:()=>Dn,EmailTemplates:()=>Me,EmailThreading:()=>Nn,SharedMailboxes:()=>kn});var ji={};Be(ji,{default:()=>Hc,handler:()=>Uc});var Ki={};Be(Ki,{CallAnalytics:()=>On,CallRecording:()=>Ln,Callbacks:()=>kt,IVRBuilder:()=>Ke});var qi={};Be(qi,{AbTesting:()=>Pe,LinkTracking:()=>_n,MmsSupport:()=>Fn,SmsAnalytics:()=>Bn,SmsCampaigns:()=>$n,SmsChatbot:()=>Gn});var au={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}},ou={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}}}};import{isAbsolute as Gt,join as yt,relative as Gs}from"node:path";var _t=".ts-cloud",Qn="TS_CLOUD_STATE_DIR",Wt=null;function uu(e){Wt=e?.trim()||null}function du(){return Boolean(process.env[Qn]?.trim()||Wt)}function Fe(){return process.env[Qn]?.trim()||Wt||_t}function Jn(...e){return yt(Fe(),...e)}function _s(e,...t){let n=Fe();return Gt(n)?yt(n,...t):yt(e,n,...t)}function mu(e,t=process.cwd()){let n=(i,s)=>{let a=Gs(i,s);return a===""||!a.startsWith("..")&&!Gt(a)},r=Gt(e)?e:yt(t,e);return n(_s(t),r)}function Yn(e){let t=e.infrastructure?.compute!=null,n=Object.values(e.environments??{}).some((r)=>r?.app!=null);return{server:t,serverless:n}}function gu(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:t}=Yn(e);return t?"serverless":"server"}function yu(e){let{server:t,serverless:n}=Yn(e);if(t&&n)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(e.mode==="server"&&n&&!t)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&t&&!n)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function hu(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function Ws(e){return typeof e==="object"&&e!==null?e:{}}function Vs(e){return e===!0||typeof e==="object"&&e!==null}function Us(e,t){let n=t?e.environments?.[t]:void 0;if(n?.domain)return n.domain;let r=Object.values(e.sites??{}),i=e.sites?.main?.domain??r.find((s)=>s.domain)?.domain;if(i)return i;return`${e.project?.slug??"app"}.local`}function Hs(e){let t=e.indexOf(".");return t>0?e.slice(t+1):void 0}function js(e,t={}){let n=e.infrastructure?.compute?.managedServices?.mail,r=Ws(n),i=t.environmentType??(t.environment?e.environments?.[t.environment]?.type:void 0),s=r.mode??(i==="production"?"server":"catcher"),a=s==="server",o=Us(e,t.environment),c=r.hostname??(a?`mail.${o}`:"localhost"),l=r.ports??{},u=a?{smtp:l.smtp??25,submission:l.submission??587,submissions:l.submissions??465,imap:l.imap??143,imaps:l.imaps??993,webmail:l.webmail??8080,managesieve:l.managesieve}:{smtp:l.smtp??1025,submission:l.submission,submissions:l.submissions,imap:l.imap,imaps:l.imaps,webmail:l.webmail??8025,managesieve:l.managesieve},m=r.tls??{},p=m.enabled??a,g=!!(m.certPath&&m.keyPath),y=(r.accounts??[]).map((K)=>({address:K.address,password:K.password,passwordPolicy:K.passwordPolicy??"initial"})),h=typeof r.dkim==="object"&&r.dkim!==null?r.dkim:{},b=r.dkim===!1?!1:r.dkim===!0||a,C=typeof r.webmail==="object"&&r.webmail!==null?r.webmail:{},T=r.webmail===!1?!1:C.enabled??!0,A=c.includes(".")&&!c.endsWith(".local")&&!/^\d+\.\d+\.\d+\.\d+$/.test(c),R=C.domain===!1?void 0:C.domain??(a&&A?c:void 0),P=C.tls??(R?!1:p),E=[...new Set(C.aliases??[])].filter((K)=>K!==R),w=r.spam??{},I=r.delivery??(a?"direct":"none"),D=r.expose??a,k=Hs(c),O=[...new Set([c,...k?[k]:[],...r.domains??[]])],ne=C.attachments?.maxFileBytes??20971520,_=C.attachments?.maxTotalBytes??20971520,q=C.attachments?.maxCount??20,F=C.undoSendSeconds??10;for(let[K,de,Oe]of[["maxFileBytes",ne,104857600],["maxTotalBytes",_,104857600],["maxCount",q,100],["undoSendSeconds",F,30]])if(!Number.isInteger(de)||de<0||de>Oe)throw Error(`Mail webmail ${K} must be an integer from 0 to ${Oe}`);return{enabled:Vs(n),mode:s,version:r.version,hostname:c,domains:O,ports:u,tls:{enabled:p,acme:p&&!g&&(m.acme??!0),certPath:m.certPath,keyPath:m.keyPath,requireForAuth:m.requireForAuth??(p&&a),acmeEmail:m.acmeEmail??y[0]?.address},dkim:{enabled:b,selector:h.selector??"default",rotate:h.rotate??!1,rotateIntervalDays:h.rotateIntervalDays??90},webmail:{enabled:T,port:C.port??u.webmail,domain:R,aliases:E,tls:P,secureCookies:C.secureCookies??(!!R||P),attachmentMaxFileBytes:ne,attachmentMaxTotalBytes:_,attachmentMaxCount:q,undoSendSeconds:F},delivery:I,sesRegion:r.sesRegion??"us-east-1",accounts:y,storagePath:r.storagePath??"/var/lib/mail",maxMessageSize:r.maxMessageSize??26214400,spam:{enabled:w.enabled??a,enforce:w.enforce??!1,junkScore:w.junkScore??5,rejectScore:w.rejectScore??12,dnsbl:w.dnsbl??a,greylist:w.greylist??!1},webhookUrl:r.webhookUrl,expose:D,bindAddress:D?"0.0.0.0":"127.0.0.1"}}function Su(e){if(!e.enabled||!e.expose)return[];let t=[e.ports.smtp,e.ports.submission,e.ports.submissions,e.ports.imap,e.ports.imaps,e.ports.managesieve].filter((n)=>typeof n==="number");if(e.webmail.enabled&&!e.webmail.domain)t.push(e.webmail.port);return[...new Set(t)].sort((n,r)=>n-r)}function Au(e){if(!e.enabled)return{};let t=e.ports.submission??e.ports.smtp,n={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(t)};if(e.mode==="server"){n.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let r=e.accounts[0];if(r)n.MAIL_USERNAME=r.address,n.MAIL_PASSWORD=r.password}else n.MAIL_ENCRYPTION="null",n.MAIL_USERNAME="null",n.MAIL_PASSWORD="null";return n}function Cu(e){if(!e.enabled||!e.webmail.enabled||!e.webmail.domain)return{};let t=[e.webmail.domain,...e.webmail.aliases];if(!Number.isInteger(e.webmail.port)||e.webmail.port<1||e.webmail.port>65535)throw Error("Mail webmail port must be between 1 and 65535");return Object.fromEntries(t.map((n,r)=>{if(!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(n))throw Error(`Invalid mail webmail hostname: ${n}`);return[`__mail_webmail_${r}`,{domain:n,proxyTo:`localhost:${e.webmail.port}`}]}))}function vu(e,t={}){let n=e.infrastructure?.compute?.proxy,r=js(e,t);if(!r.enabled||!r.webmail.enabled||!r.webmail.domain)return n;return{engine:"rpx",onDemandTls:!0,onDemandTlsEmail:r.tls.acmeEmail??`webmaster@${r.webmail.domain}`,...n}}function Ru(e){if(e.cloud?.provider)return e.cloud.provider;if(e.ssh?.hosts?.length)return"ssh";if(e.hetzner?.apiToken)return"hetzner";return"aws"}class Ks{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,t){return this.template.Resources[e]=t,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,t){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=t,this}addOutput(e,t){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=t,this}addMetadata(e,t){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[e]=t,this}hasResource(e){return e in this.template.Resources}getResources(){return this.template.Resources}build(){return this.template}toJSON(e=!0){return JSON.stringify(this.template,null,e?2:0)}toYAML(){return this.convertToYAML(this.template)}convertToYAML(e,t=0){let n=" ".repeat(t),r="";for(let[i,s]of Object.entries(e)){if(s===null||s===void 0)continue;if(typeof s==="object"&&!Array.isArray(s))r+=`${n}${i}:
14
14
  ${this.convertToYAML(s,t+1)}`;else if(Array.isArray(s)){r+=`${n}${i}:
15
15
  `;for(let a of s)if(typeof a==="object")r+=`${n} -
16
16
  ${this.convertToYAML(a,t+2)}`;else r+=`${n} - ${a}
17
17
  `}else r+=`${n}${i}: ${s}
18
- `}return r}}function qs(e){let t=[],n=[],r=[];if(zs(e,t),e.Resources)Qs(e.Resources,t,n);else t.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});if(e.Parameters)Js(e.Parameters,t,n);if(e.Outputs)Ys(e.Outputs,t);Zs(e,t);let i=Xs(e);if(i.length>0)for(let s of i)t.push({path:"Resources",message:`Circular dependency detected: ${s.join(" → ")}`,severity:"error"});return ta(e,n,r),{valid:t.length===0,errors:t,warnings:n,info:r}}function zs(e,t){if(!e.AWSTemplateFormatVersion)t.push({path:"AWSTemplateFormatVersion",message:"Template should specify AWSTemplateFormatVersion",severity:"error"});else if(e.AWSTemplateFormatVersion!=="2010-09-09")t.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion must be "2010-09-09"',severity:"error"})}function Qs(e,t,n){let r=Object.keys(e);if(r.length===0){t.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});return}if(r.length>500)n.push({path:"Resources",message:`Template contains ${r.length} resources (limit is 500)`,severity:"warning"});for(let i of r){let s=e[i];if(!/^[a-zA-Z0-9]+$/.test(i))t.push({path:`Resources.${i}`,message:"Logical ID must contain only alphanumeric characters",severity:"error"});if(!s.Type)t.push({path:`Resources.${i}.Type`,message:"Resource Type is required",severity:"error"});else if(!s.Type.startsWith("AWS::")&&!s.Type.startsWith("Custom::"))t.push({path:`Resources.${i}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(s.DeletionPolicy&&!["Delete","Retain","Snapshot"].includes(s.DeletionPolicy))t.push({path:`Resources.${i}.DeletionPolicy`,message:'DeletionPolicy must be "Delete", "Retain", or "Snapshot"',severity:"error"});if(!s.DeletionPolicy&&Zn(s.Type))n.push({path:`Resources.${i}.DeletionPolicy`,message:`${s.Type} should specify DeletionPolicy to prevent accidental data loss`,severity:"warning"})}}function Js(e,t,n){let r=Object.keys(e);if(r.length>200)n.push({path:"Parameters",message:`Template contains ${r.length} parameters (limit is 200)`,severity:"warning"});for(let i of r){let s=e[i];if(!s.Type)t.push({path:`Parameters.${i}.Type`,message:"Parameter Type is required",severity:"error"});let a=["String","Number","List<Number>","CommaDelimitedList","AWS::EC2::AvailabilityZone::Name","AWS::EC2::Image::Id","AWS::EC2::Instance::Id","AWS::EC2::KeyPair::KeyName","AWS::EC2::SecurityGroup::GroupName","AWS::EC2::SecurityGroup::Id","AWS::EC2::Subnet::Id","AWS::EC2::Volume::Id","AWS::EC2::VPC::Id","AWS::Route53::HostedZone::Id","List<AWS::EC2::AvailabilityZone::Name>","List<AWS::EC2::Image::Id>","List<AWS::EC2::Instance::Id>","List<AWS::EC2::SecurityGroup::GroupName>","List<AWS::EC2::SecurityGroup::Id>","List<AWS::EC2::Subnet::Id>","List<AWS::EC2::Volume::Id>","List<AWS::EC2::VPC::Id>","List<AWS::Route53::HostedZone::Id>","AWS::SSM::Parameter::Name","AWS::SSM::Parameter::Value<String>","AWS::SSM::Parameter::Value<List<String>>","AWS::SSM::Parameter::Value<CommaDelimitedList>"];if(s.Type&&!a.includes(s.Type))t.push({path:`Parameters.${i}.Type`,message:`Invalid parameter type: ${s.Type}`,severity:"error"})}}function Ys(e,t){let n=Object.keys(e);for(let r of n)if(!e[r].Value)t.push({path:`Outputs.${r}.Value`,message:"Output Value is required",severity:"error"})}function Zs(e,t){let n=e.Resources||{},r=e.Parameters||{},i=new Set(Object.keys(n)),s=new Set(Object.keys(r));function a(o,c){if(typeof o!=="object"||o===null)return;if(o.Ref){let l=o.Ref;if(!i.has(l)&&!s.has(l)&&l!=="AWS::Region"&&l!=="AWS::AccountId"&&l!=="AWS::StackName"&&l!=="AWS::StackId"&&l!=="AWS::URLSuffix"&&l!=="AWS::Partition"&&l!=="AWS::NoValue")t.push({path:c,message:`Reference to non-existent resource or parameter: ${l}`,severity:"error"})}if(o["Fn::GetAtt"]){let l=o["Fn::GetAtt"];if(Array.isArray(l)&&l.length>=1){let u=l[0];if(!i.has(u))t.push({path:c,message:`GetAtt references non-existent resource: ${u}`,severity:"error"})}}for(let l in o)a(o[l],`${c}.${l}`)}for(let o in n)a(n[o],`Resources.${o}`);if(e.Outputs)for(let o in e.Outputs)a(e.Outputs[o],`Outputs.${o}`)}function Xs(e){let t=e.Resources||{},n=new Map;for(let o in t){let c=new Set,l=t[o];if(l.DependsOn)if(Array.isArray(l.DependsOn))l.DependsOn.forEach((m)=>c.add(m));else c.add(l.DependsOn);ea(l).forEach((m)=>c.add(m)),n.set(o,c)}let r=[],i=new Set,s=new Set;function a(o,c){i.add(o),s.add(o),c.push(o);let l=n.get(o)||new Set;for(let u of l)if(!i.has(u))a(u,[...c]);else if(s.has(u)){let m=c.indexOf(u),p=[...c.slice(m),u];r.push(p)}s.delete(o)}for(let o of n.keys())if(!i.has(o))a(o,[]);return r}function ea(e){let t=new Set;function n(r){if(typeof r!=="object"||r===null)return;if(r.Ref&&typeof r.Ref==="string"){if(!r.Ref.startsWith("AWS::"))t.add(r.Ref)}if(r["Fn::GetAtt"]&&Array.isArray(r["Fn::GetAtt"]))t.add(r["Fn::GetAtt"][0]);for(let i in r)n(r[i])}return n(e),t}function Zn(e){return["AWS::S3::Bucket","AWS::DynamoDB::Table","AWS::RDS::DBInstance","AWS::RDS::DBCluster","AWS::ElastiCache::CacheCluster","AWS::ElastiCache::ReplicationGroup","AWS::EFS::FileSystem","AWS::OpenSearchService::Domain"].includes(e)}function ta(e,t,n){let r=e.Resources||{};if(!e.Description)n.push({path:"Description",message:"Consider adding a Description to the template",severity:"info"});for(let i in r){let s=r[i],a=s.Properties;if(a&&!a.Tags&&na(s.Type))n.push({path:`Resources.${i}`,message:`Consider adding Tags to ${s.Type}`,severity:"info"});if(Zn(s.Type)){if(s.Type==="AWS::S3::Bucket"&&!a?.BucketEncryption)t.push({path:`Resources.${i}`,message:"S3 bucket should enable encryption",severity:"warning"});if(s.Type==="AWS::RDS::DBInstance"&&!a?.StorageEncrypted)t.push({path:`Resources.${i}`,message:"RDS instance should enable storage encryption",severity:"warning"})}}}function na(e){return!["AWS::CloudFormation::Stack","AWS::CloudFormation::WaitCondition","AWS::CloudFormation::WaitConditionHandle"].includes(e)}function ra(e){let t=[],n=[],r=[],i=Buffer.byteLength(e,"utf8"),s=i/1024,a=51200,o=460800;if(i>460800)t.push({path:"Template",message:`Template size (${s.toFixed(2)} KB) exceeds maximum size of 450 KB`,severity:"error"});else if(i>51200)n.push({path:"Template",message:`Template size (${s.toFixed(2)} KB) exceeds 50 KB. Must use S3 for deployment.`,severity:"warning"});return{valid:t.length===0,errors:t,warnings:n,info:r}}function ia(e){let t=[],n=[],r=[],i=e.Resources||{},s=e.Parameters||{},a=e.Outputs||{};if(Object.keys(i).length>500)t.push({path:"Resources",message:`Template has ${Object.keys(i).length} resources (limit is 500)`,severity:"error"});if(Object.keys(s).length>200)t.push({path:"Parameters",message:`Template has ${Object.keys(s).length} parameters (limit is 200)`,severity:"error"});if(Object.keys(a).length>200)t.push({path:"Outputs",message:`Template has ${Object.keys(a).length} outputs (limit is 200)`,severity:"error"});return{valid:t.length===0,errors:t,warnings:n,info:r}}var C={Ref:(e)=>({Ref:e}),GetAtt:(e,t)=>({"Fn::GetAtt":[e,t]}),Sub:(e,t)=>{if(t)return{"Fn::Sub":[e,t]};return{"Fn::Sub":e}},Join:(e,t)=>({"Fn::Join":[e,t]}),Select:(e,t)=>({"Fn::Select":[e,t]}),Split:(e,t)=>({"Fn::Split":[e,t]}),GetAZs:(e="")=>({"Fn::GetAZs":e}),ImportValue:(e)=>({"Fn::ImportValue":e}),If:(e,t,n)=>({"Fn::If":[e,t,n]}),Equals:(e,t)=>({"Fn::Equals":[e,t]}),And:(...e)=>({"Fn::And":e}),Or:(...e)=>({"Fn::Or":e}),Not:(e)=>({"Fn::Not":[e]}),Base64:(e)=>({"Fn::Base64":e})},sa={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 S(e){let{slug:t,environment:n,resourceType:r,timestamp:i,suffix:s}=e,a=[t,n,r];if(i)a.push(i);if(s)a.push(s);return a.join("-")}function f(e){return e.split("-").map((t)=>t.charAt(0).toUpperCase()+t.slice(1)).join("")}function xu(){return Date.now().toString()}function ku(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function Lu(e,t){return e.project.stackName??`${e.project.slug}-${t}`}function Ou(e,t,n,r){return n.stackName??`${e.project.slug}-${r}-${t}-site`}function $u(e,t){return`${e.project.slug}-${t}`}function Bu(e,t,n,r){if(r)return r;if(n==="main")return`${e}-${t}-site`;return`${e}-${t}-${n}`}function Fu(e,t,n,r){return r??`${e}-${t}-${n}`}function Gu(e,t){return`${e}-${t}-deploy`}function _u(e,t){return`${e.project.slug}-${t}-app`}function Wu(e,t){return`${e}-${t}-deployments`}function Xn(e,t){return`${e}-${t}-assets`}class aa{nodes=new Map;addResource(e,t){let n=this.extractDependencies(t);this.nodes.set(e,{logicalId:e,resource:t,dependencies:n})}extractDependencies(e){let t=new Set;if(e.DependsOn)if(Array.isArray(e.DependsOn))e.DependsOn.forEach((n)=>t.add(n));else t.add(e.DependsOn);return this.findReferences(e.Properties||{},t),t}findReferences(e,t){if(!e||typeof e!=="object")return;if("Ref"in e&&typeof e.Ref==="string"){if(!e.Ref.startsWith("AWS::"))t.add(e.Ref)}if("Fn::GetAtt"in e&&Array.isArray(e["Fn::GetAtt"]))t.add(e["Fn::GetAtt"][0]);for(let n of Object.values(e))if(typeof n==="object")this.findReferences(n,t)}topologicalSort(){let e=[],t=new Set,n=new Set,r=(i)=>{if(t.has(i))return;if(n.has(i))throw Error(`Circular dependency detected: ${i}`);n.add(i);let s=this.nodes.get(i);if(s)for(let a of s.dependencies)r(a);n.delete(i),t.add(i),e.push(i)};for(let i of this.nodes.keys())r(i);return e}validate(){for(let[e,t]of this.nodes.entries())for(let n of t.dependencies)if(!this.nodes.has(n))throw Error(`Resource "${e}" depends on "${n}" which does not exist`)}getDependents(e){let t=[];for(let[n,r]of this.nodes.entries())if(r.dependencies.has(e))t.push(n);return t}}function Hu(e,t){let n=[],r=[],i=[],s=[],a=[],o=e.Resources||{},c=t.Resources||{},l=new Set([...Object.keys(o),...Object.keys(c)]);for(let m of l){let p=o[m],g=c[m];if(!p&&g)n.push({logicalId:m,action:"add",resourceType:g.Type});else if(p&&!g)r.push({logicalId:m,action:"remove",resourceType:p.Type});else if(p&&g)if(p.Type!==g.Type)s.push({logicalId:m,action:"replace",resourceType:g.Type,reason:`Type changed from ${p.Type} to ${g.Type}`});else{let y=er(p.Properties||{},g.Properties||{});if(y.length>0)if(oa(p.Type,y))s.push({logicalId:m,action:"replace",resourceType:g.Type,changes:y,reason:"Property changes require replacement"});else i.push({logicalId:m,action:"update",resourceType:g.Type,changes:y});else a.push(m)}}let u=ca([...r,...s,...i]);return{added:n,removed:r,updated:i,replaced:s,unchanged:a,summary:{totalChanges:n.length+r.length+i.length+s.length,requiresReplacement:s.length>0,dangerousChanges:u}}}function er(e,t,n=""){let r=[],i=new Set([...Object.keys(e),...Object.keys(t)]);for(let s of i){let a=n?`${n}.${s}`:s,o=e[s],c=t[s];if(o===void 0&&c!==void 0)r.push({path:a,oldValue:void 0,newValue:c});else if(o!==void 0&&c===void 0)r.push({path:a,oldValue:o,newValue:void 0});else if(typeof o!==typeof c)r.push({path:a,oldValue:o,newValue:c});else if(typeof o==="object"&&o!==null)if(Array.isArray(o)&&Array.isArray(c)){if(JSON.stringify(o)!==JSON.stringify(c))r.push({path:a,oldValue:o,newValue:c})}else if(!Array.isArray(o)&&!Array.isArray(c)){let l=er(o,c,a);r.push(...l)}else r.push({path:a,oldValue:o,newValue:c});else if(o!==c)r.push({path:a,oldValue:o,newValue:c})}return r}function oa(e,t){let r={"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"])}[e];if(!r)return!1;for(let i of t){let s=i.path.split(".")[0];if(r.has(s))return!0}return!1}function ca(e){let t=[];for(let n of e){if(n.action==="remove"&&(n.resourceType==="AWS::RDS::DBInstance"||n.resourceType==="AWS::DynamoDB::Table"||n.resourceType==="AWS::ElastiCache::CacheCluster"))t.push(`Removing ${n.resourceType} ${n.logicalId} - data loss risk!`);if(n.action==="replace"&&(n.resourceType==="AWS::RDS::DBInstance"||n.resourceType==="AWS::DynamoDB::Table"))t.push(`Replacing ${n.resourceType} ${n.logicalId} - data loss risk!`);if((n.action==="remove"||n.action==="replace")&&n.resourceType==="AWS::S3::Bucket")t.push(`${n.action==="remove"?"Removing":"Replacing"} S3 bucket ${n.logicalId} - data loss risk!`);if(n.action==="replace"&&n.resourceType==="AWS::EC2::Instance")t.push(`Replacing EC2 instance ${n.logicalId} - downtime expected`);if(n.action==="update"&&n.resourceType==="AWS::EC2::SecurityGroup")t.push(`Updating security group ${n.logicalId} - may affect connectivity`);if((n.action==="update"||n.action==="replace")&&(n.resourceType==="AWS::IAM::Role"||n.resourceType==="AWS::IAM::Policy"))t.push(`Modifying IAM ${n.resourceType.split("::")[2]} ${n.logicalId} - may affect permissions`)}return t}function ju(e){let t=[];if(t.push(`=== Stack Update Analysis ===
18
+ `}return r}}function qs(e){let t=[],n=[],r=[];if(zs(e,t),e.Resources)Qs(e.Resources,t,n);else t.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});if(e.Parameters)Js(e.Parameters,t,n);if(e.Outputs)Ys(e.Outputs,t);Zs(e,t);let i=Xs(e);if(i.length>0)for(let s of i)t.push({path:"Resources",message:`Circular dependency detected: ${s.join(" → ")}`,severity:"error"});return ta(e,n,r),{valid:t.length===0,errors:t,warnings:n,info:r}}function zs(e,t){if(!e.AWSTemplateFormatVersion)t.push({path:"AWSTemplateFormatVersion",message:"Template should specify AWSTemplateFormatVersion",severity:"error"});else if(e.AWSTemplateFormatVersion!=="2010-09-09")t.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion must be "2010-09-09"',severity:"error"})}function Qs(e,t,n){let r=Object.keys(e);if(r.length===0){t.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});return}if(r.length>500)n.push({path:"Resources",message:`Template contains ${r.length} resources (limit is 500)`,severity:"warning"});for(let i of r){let s=e[i];if(!/^[a-zA-Z0-9]+$/.test(i))t.push({path:`Resources.${i}`,message:"Logical ID must contain only alphanumeric characters",severity:"error"});if(!s.Type)t.push({path:`Resources.${i}.Type`,message:"Resource Type is required",severity:"error"});else if(!s.Type.startsWith("AWS::")&&!s.Type.startsWith("Custom::"))t.push({path:`Resources.${i}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(s.DeletionPolicy&&!["Delete","Retain","Snapshot"].includes(s.DeletionPolicy))t.push({path:`Resources.${i}.DeletionPolicy`,message:'DeletionPolicy must be "Delete", "Retain", or "Snapshot"',severity:"error"});if(!s.DeletionPolicy&&Zn(s.Type))n.push({path:`Resources.${i}.DeletionPolicy`,message:`${s.Type} should specify DeletionPolicy to prevent accidental data loss`,severity:"warning"})}}function Js(e,t,n){let r=Object.keys(e);if(r.length>200)n.push({path:"Parameters",message:`Template contains ${r.length} parameters (limit is 200)`,severity:"warning"});for(let i of r){let s=e[i];if(!s.Type)t.push({path:`Parameters.${i}.Type`,message:"Parameter Type is required",severity:"error"});let a=["String","Number","List<Number>","CommaDelimitedList","AWS::EC2::AvailabilityZone::Name","AWS::EC2::Image::Id","AWS::EC2::Instance::Id","AWS::EC2::KeyPair::KeyName","AWS::EC2::SecurityGroup::GroupName","AWS::EC2::SecurityGroup::Id","AWS::EC2::Subnet::Id","AWS::EC2::Volume::Id","AWS::EC2::VPC::Id","AWS::Route53::HostedZone::Id","List<AWS::EC2::AvailabilityZone::Name>","List<AWS::EC2::Image::Id>","List<AWS::EC2::Instance::Id>","List<AWS::EC2::SecurityGroup::GroupName>","List<AWS::EC2::SecurityGroup::Id>","List<AWS::EC2::Subnet::Id>","List<AWS::EC2::Volume::Id>","List<AWS::EC2::VPC::Id>","List<AWS::Route53::HostedZone::Id>","AWS::SSM::Parameter::Name","AWS::SSM::Parameter::Value<String>","AWS::SSM::Parameter::Value<List<String>>","AWS::SSM::Parameter::Value<CommaDelimitedList>"];if(s.Type&&!a.includes(s.Type))t.push({path:`Parameters.${i}.Type`,message:`Invalid parameter type: ${s.Type}`,severity:"error"})}}function Ys(e,t){let n=Object.keys(e);for(let r of n)if(!e[r].Value)t.push({path:`Outputs.${r}.Value`,message:"Output Value is required",severity:"error"})}function Zs(e,t){let n=e.Resources||{},r=e.Parameters||{},i=new Set(Object.keys(n)),s=new Set(Object.keys(r));function a(o,c){if(typeof o!=="object"||o===null)return;if(o.Ref){let l=o.Ref;if(!i.has(l)&&!s.has(l)&&l!=="AWS::Region"&&l!=="AWS::AccountId"&&l!=="AWS::StackName"&&l!=="AWS::StackId"&&l!=="AWS::URLSuffix"&&l!=="AWS::Partition"&&l!=="AWS::NoValue")t.push({path:c,message:`Reference to non-existent resource or parameter: ${l}`,severity:"error"})}if(o["Fn::GetAtt"]){let l=o["Fn::GetAtt"];if(Array.isArray(l)&&l.length>=1){let u=l[0];if(!i.has(u))t.push({path:c,message:`GetAtt references non-existent resource: ${u}`,severity:"error"})}}for(let l in o)a(o[l],`${c}.${l}`)}for(let o in n)a(n[o],`Resources.${o}`);if(e.Outputs)for(let o in e.Outputs)a(e.Outputs[o],`Outputs.${o}`)}function Xs(e){let t=e.Resources||{},n=new Map;for(let o in t){let c=new Set,l=t[o];if(l.DependsOn)if(Array.isArray(l.DependsOn))l.DependsOn.forEach((m)=>c.add(m));else c.add(l.DependsOn);ea(l).forEach((m)=>c.add(m)),n.set(o,c)}let r=[],i=new Set,s=new Set;function a(o,c){i.add(o),s.add(o),c.push(o);let l=n.get(o)||new Set;for(let u of l)if(!i.has(u))a(u,[...c]);else if(s.has(u)){let m=c.indexOf(u),p=[...c.slice(m),u];r.push(p)}s.delete(o)}for(let o of n.keys())if(!i.has(o))a(o,[]);return r}function ea(e){let t=new Set;function n(r){if(typeof r!=="object"||r===null)return;if(r.Ref&&typeof r.Ref==="string"){if(!r.Ref.startsWith("AWS::"))t.add(r.Ref)}if(r["Fn::GetAtt"]&&Array.isArray(r["Fn::GetAtt"]))t.add(r["Fn::GetAtt"][0]);for(let i in r)n(r[i])}return n(e),t}function Zn(e){return["AWS::S3::Bucket","AWS::DynamoDB::Table","AWS::RDS::DBInstance","AWS::RDS::DBCluster","AWS::ElastiCache::CacheCluster","AWS::ElastiCache::ReplicationGroup","AWS::EFS::FileSystem","AWS::OpenSearchService::Domain"].includes(e)}function ta(e,t,n){let r=e.Resources||{};if(!e.Description)n.push({path:"Description",message:"Consider adding a Description to the template",severity:"info"});for(let i in r){let s=r[i],a=s.Properties;if(a&&!a.Tags&&na(s.Type))n.push({path:`Resources.${i}`,message:`Consider adding Tags to ${s.Type}`,severity:"info"});if(Zn(s.Type)){if(s.Type==="AWS::S3::Bucket"&&!a?.BucketEncryption)t.push({path:`Resources.${i}`,message:"S3 bucket should enable encryption",severity:"warning"});if(s.Type==="AWS::RDS::DBInstance"&&!a?.StorageEncrypted)t.push({path:`Resources.${i}`,message:"RDS instance should enable storage encryption",severity:"warning"})}}}function na(e){return!["AWS::CloudFormation::Stack","AWS::CloudFormation::WaitCondition","AWS::CloudFormation::WaitConditionHandle"].includes(e)}function ra(e){let t=[],n=[],r=[],i=Buffer.byteLength(e,"utf8"),s=i/1024,a=51200,o=460800;if(i>460800)t.push({path:"Template",message:`Template size (${s.toFixed(2)} KB) exceeds maximum size of 450 KB`,severity:"error"});else if(i>51200)n.push({path:"Template",message:`Template size (${s.toFixed(2)} KB) exceeds 50 KB. Must use S3 for deployment.`,severity:"warning"});return{valid:t.length===0,errors:t,warnings:n,info:r}}function ia(e){let t=[],n=[],r=[],i=e.Resources||{},s=e.Parameters||{},a=e.Outputs||{};if(Object.keys(i).length>500)t.push({path:"Resources",message:`Template has ${Object.keys(i).length} resources (limit is 500)`,severity:"error"});if(Object.keys(s).length>200)t.push({path:"Parameters",message:`Template has ${Object.keys(s).length} parameters (limit is 200)`,severity:"error"});if(Object.keys(a).length>200)t.push({path:"Outputs",message:`Template has ${Object.keys(a).length} outputs (limit is 200)`,severity:"error"});return{valid:t.length===0,errors:t,warnings:n,info:r}}var v={Ref:(e)=>({Ref:e}),GetAtt:(e,t)=>({"Fn::GetAtt":[e,t]}),Sub:(e,t)=>{if(t)return{"Fn::Sub":[e,t]};return{"Fn::Sub":e}},Join:(e,t)=>({"Fn::Join":[e,t]}),Select:(e,t)=>({"Fn::Select":[e,t]}),Split:(e,t)=>({"Fn::Split":[e,t]}),GetAZs:(e="")=>({"Fn::GetAZs":e}),ImportValue:(e)=>({"Fn::ImportValue":e}),If:(e,t,n)=>({"Fn::If":[e,t,n]}),Equals:(e,t)=>({"Fn::Equals":[e,t]}),And:(...e)=>({"Fn::And":e}),Or:(...e)=>({"Fn::Or":e}),Not:(e)=>({"Fn::Not":[e]}),Base64:(e)=>({"Fn::Base64":e})},sa={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 S(e){let{slug:t,environment:n,resourceType:r,timestamp:i,suffix:s}=e,a=[t,n,r];if(i)a.push(i);if(s)a.push(s);return a.join("-")}function f(e){return e.split("-").map((t)=>t.charAt(0).toUpperCase()+t.slice(1)).join("")}function xu(){return Date.now().toString()}function ku(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function Lu(e,t){return e.project.stackName??`${e.project.slug}-${t}`}function Ou(e,t,n,r){return n.stackName??`${e.project.slug}-${r}-${t}-site`}function $u(e,t){return`${e.project.slug}-${t}`}function Bu(e,t,n,r){if(r)return r;if(n==="main")return`${e}-${t}-site`;return`${e}-${t}-${n}`}function Fu(e,t,n,r){return r??`${e}-${t}-${n}`}function Gu(e,t){return`${e}-${t}-deploy`}function _u(e,t){return`${e.project.slug}-${t}-app`}function Wu(e,t){return`${e}-${t}-deployments`}function Xn(e,t){return`${e}-${t}-assets`}class aa{nodes=new Map;addResource(e,t){let n=this.extractDependencies(t);this.nodes.set(e,{logicalId:e,resource:t,dependencies:n})}extractDependencies(e){let t=new Set;if(e.DependsOn)if(Array.isArray(e.DependsOn))e.DependsOn.forEach((n)=>t.add(n));else t.add(e.DependsOn);return this.findReferences(e.Properties||{},t),t}findReferences(e,t){if(!e||typeof e!=="object")return;if("Ref"in e&&typeof e.Ref==="string"){if(!e.Ref.startsWith("AWS::"))t.add(e.Ref)}if("Fn::GetAtt"in e&&Array.isArray(e["Fn::GetAtt"]))t.add(e["Fn::GetAtt"][0]);for(let n of Object.values(e))if(typeof n==="object")this.findReferences(n,t)}topologicalSort(){let e=[],t=new Set,n=new Set,r=(i)=>{if(t.has(i))return;if(n.has(i))throw Error(`Circular dependency detected: ${i}`);n.add(i);let s=this.nodes.get(i);if(s)for(let a of s.dependencies)r(a);n.delete(i),t.add(i),e.push(i)};for(let i of this.nodes.keys())r(i);return e}validate(){for(let[e,t]of this.nodes.entries())for(let n of t.dependencies)if(!this.nodes.has(n))throw Error(`Resource "${e}" depends on "${n}" which does not exist`)}getDependents(e){let t=[];for(let[n,r]of this.nodes.entries())if(r.dependencies.has(e))t.push(n);return t}}function Hu(e,t){let n=[],r=[],i=[],s=[],a=[],o=e.Resources||{},c=t.Resources||{},l=new Set([...Object.keys(o),...Object.keys(c)]);for(let m of l){let p=o[m],g=c[m];if(!p&&g)n.push({logicalId:m,action:"add",resourceType:g.Type});else if(p&&!g)r.push({logicalId:m,action:"remove",resourceType:p.Type});else if(p&&g)if(p.Type!==g.Type)s.push({logicalId:m,action:"replace",resourceType:g.Type,reason:`Type changed from ${p.Type} to ${g.Type}`});else{let y=er(p.Properties||{},g.Properties||{});if(y.length>0)if(oa(p.Type,y))s.push({logicalId:m,action:"replace",resourceType:g.Type,changes:y,reason:"Property changes require replacement"});else i.push({logicalId:m,action:"update",resourceType:g.Type,changes:y});else a.push(m)}}let u=ca([...r,...s,...i]);return{added:n,removed:r,updated:i,replaced:s,unchanged:a,summary:{totalChanges:n.length+r.length+i.length+s.length,requiresReplacement:s.length>0,dangerousChanges:u}}}function er(e,t,n=""){let r=[],i=new Set([...Object.keys(e),...Object.keys(t)]);for(let s of i){let a=n?`${n}.${s}`:s,o=e[s],c=t[s];if(o===void 0&&c!==void 0)r.push({path:a,oldValue:void 0,newValue:c});else if(o!==void 0&&c===void 0)r.push({path:a,oldValue:o,newValue:void 0});else if(typeof o!==typeof c)r.push({path:a,oldValue:o,newValue:c});else if(typeof o==="object"&&o!==null)if(Array.isArray(o)&&Array.isArray(c)){if(JSON.stringify(o)!==JSON.stringify(c))r.push({path:a,oldValue:o,newValue:c})}else if(!Array.isArray(o)&&!Array.isArray(c)){let l=er(o,c,a);r.push(...l)}else r.push({path:a,oldValue:o,newValue:c});else if(o!==c)r.push({path:a,oldValue:o,newValue:c})}return r}function oa(e,t){let r={"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"])}[e];if(!r)return!1;for(let i of t){let s=i.path.split(".")[0];if(r.has(s))return!0}return!1}function ca(e){let t=[];for(let n of e){if(n.action==="remove"&&(n.resourceType==="AWS::RDS::DBInstance"||n.resourceType==="AWS::DynamoDB::Table"||n.resourceType==="AWS::ElastiCache::CacheCluster"))t.push(`Removing ${n.resourceType} ${n.logicalId} - data loss risk!`);if(n.action==="replace"&&(n.resourceType==="AWS::RDS::DBInstance"||n.resourceType==="AWS::DynamoDB::Table"))t.push(`Replacing ${n.resourceType} ${n.logicalId} - data loss risk!`);if((n.action==="remove"||n.action==="replace")&&n.resourceType==="AWS::S3::Bucket")t.push(`${n.action==="remove"?"Removing":"Replacing"} S3 bucket ${n.logicalId} - data loss risk!`);if(n.action==="replace"&&n.resourceType==="AWS::EC2::Instance")t.push(`Replacing EC2 instance ${n.logicalId} - downtime expected`);if(n.action==="update"&&n.resourceType==="AWS::EC2::SecurityGroup")t.push(`Updating security group ${n.logicalId} - may affect connectivity`);if((n.action==="update"||n.action==="replace")&&(n.resourceType==="AWS::IAM::Role"||n.resourceType==="AWS::IAM::Policy"))t.push(`Modifying IAM ${n.resourceType.split("::")[2]} ${n.logicalId} - may affect permissions`)}return t}function ju(e){let t=[];if(t.push(`=== Stack Update Analysis ===
19
19
  `),e.summary.totalChanges===0)return t.push(`No changes detected.
20
20
  `),t.join(`
21
21
  `);if(t.push(`Total changes: ${e.summary.totalChanges}`),t.push(`Requires replacement: ${e.summary.requiresReplacement?"Yes":"No"}
22
22
  `),e.summary.dangerousChanges.length>0){t.push("⚠️ DANGEROUS CHANGES DETECTED:");for(let n of e.summary.dangerousChanges)t.push(` • ${n}`);t.push("")}if(e.added.length>0){t.push(`✅ Resources to Add (${e.added.length}):`);for(let n of e.added)t.push(` + ${n.logicalId} (${n.resourceType})`);t.push("")}if(e.removed.length>0){t.push(`❌ Resources to Remove (${e.removed.length}):`);for(let n of e.removed)t.push(` - ${n.logicalId} (${n.resourceType})`);t.push("")}if(e.replaced.length>0){t.push(`\uD83D\uDD04 Resources to Replace (${e.replaced.length}):`);for(let n of e.replaced){if(t.push(` ~ ${n.logicalId} (${n.resourceType})`),n.reason)t.push(` Reason: ${n.reason}`);if(n.changes){for(let r of n.changes.slice(0,3))t.push(` • ${r.path}: ${JSON.stringify(r.oldValue)} → ${JSON.stringify(r.newValue)}`);if(n.changes.length>3)t.push(` ... and ${n.changes.length-3} more changes`)}}t.push("")}if(e.updated.length>0){t.push(`\uD83D\uDCDD Resources to Update (${e.updated.length}):`);for(let n of e.updated)if(t.push(` ~ ${n.logicalId} (${n.resourceType})`),n.changes){for(let r of n.changes.slice(0,3))t.push(` • ${r.path}: ${JSON.stringify(r.oldValue)} → ${JSON.stringify(r.newValue)}`);if(n.changes.length>3)t.push(` ... and ${n.changes.length-3} more changes`)}t.push("")}if(e.unchanged.length>0)t.push(`⚪ Unchanged Resources (${e.unchanged.length})`);return t.join(`
23
- `)}import{existsSync as Ye,readdirSync as la}from"node:fs";import{join as Ae}from"node:path";class Ie{static createBucket(e){let{name:t,bucketName:n,slug:r,environment:i,public:s=!1,versioning:a=!1,website:o=!1,encryption:c=!0,intelligentTiering:l=!1,cors:u,lifecycleRules:m}=e,p=n??S({slug:r,environment:i,resourceType:"s3",suffix:t}),g=f(p),y={Type:"AWS::S3::Bucket",Properties:{BucketName:p}};if(c)y.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(a)y.Properties.VersioningConfiguration={Status:"Enabled"};if(o)y.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!s)y.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(u&&u.length>0)y.Properties.CorsConfiguration={CorsRules:u.map((b)=>({AllowedOrigins:b.allowedOrigins,AllowedMethods:b.allowedMethods,AllowedHeaders:b.allowedHeaders,MaxAge:b.maxAge}))};if(m&&m.length>0)y.Properties.LifecycleConfiguration={Rules:m.map((b)=>({Id:b.id,Status:b.enabled?"Enabled":"Disabled",ExpirationInDays:b.expirationDays,Transitions:b.transitions?.map((v)=>({TransitionInDays:v.days,StorageClass:v.storageClass}))}))};if(l&&m){let b={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!y.Properties.LifecycleConfiguration)y.Properties.LifecycleConfiguration={Rules:[]};y.Properties.LifecycleConfiguration.Rules.push({Id:b.id,Status:"Enabled",Transitions:b.transitions?.map((v)=>({TransitionInDays:v.days,StorageClass:v.storageClass}))})}let h;if(s)h={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:C.Ref(g),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[C.Join("",[C.GetAtt(g,"Arn"),"/*"])]}]}}};return{bucket:y,bucketPolicy:h,logicalId:g}}static enableVersioning(e){if(!e.Properties)e.Properties={};return e.Properties.VersioningConfiguration={Status:"Enabled"},e}static enableWebsiteHosting(e,t="index.html",n="error.html"){if(!e.Properties)e.Properties={};return e.Properties.WebsiteConfiguration={IndexDocument:t,ErrorDocument:n},e}static setLifecycleRules(e,t){if(!e.Properties)e.Properties={};return e.Properties.LifecycleConfiguration={Rules:t.map((n)=>({Id:n.id,Status:n.enabled?"Enabled":"Disabled",ExpirationInDays:n.expirationDays,Transitions:n.transitions?.map((r)=>({TransitionInDays:r.days,StorageClass:r.storageClass}))}))},e}static enableIntelligentTiering(e){if(!e.Properties)e.Properties={};if(!e.Properties.LifecycleConfiguration)e.Properties.LifecycleConfiguration={Rules:[]};return e.Properties.LifecycleConfiguration.Rules.push({Id:"IntelligentTieringRule",Status:"Enabled",Transitions:[{TransitionInDays:0,StorageClass:"INTELLIGENT_TIERING"}]}),e}static addLambdaNotification(e,t){if(!e.Properties)e.Properties={};if(!e.Properties.NotificationConfiguration)e.Properties.NotificationConfiguration={};if(!e.Properties.NotificationConfiguration.LambdaConfigurations)e.Properties.NotificationConfiguration.LambdaConfigurations=[];let n={Event:t.events[0],Function:t.functionArn};if(t.filter)n.Filter={S3Key:{Rules:[...t.filter.prefix?[{Name:"prefix",Value:t.filter.prefix}]:[],...t.filter.suffix?[{Name:"suffix",Value:t.filter.suffix}]:[]]}};for(let r of t.events){let i={...n,Event:r};e.Properties.NotificationConfiguration.LambdaConfigurations.push(i)}return e}static Notifications={onObjectCreated:(e)=>({functionArn:e,events:["s3:ObjectCreated:*"]}),onObjectRemoved:(e)=>({functionArn:e,events:["s3:ObjectRemoved:*"]}),onImageUpload:(e,t)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:t,suffix:".jpg"}}),onFileType:(e,t,n)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:n,suffix:t}}),onFolderUpload:(e,t)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:t.endsWith("/")?t:`${t}/`}})};static createBackupPlan(e){let{name:t,slug:n,environment:r,bucketLogicalIds:i,retentionDays:s,schedule:a="cron(0 5 * * ? *)",vaultName:o,enableContinuousBackup:c=!1,moveToColdStorageAfterDays:l}=e,u=o||S({slug:n,environment:r,resourceType:"backup-vault",suffix:t}),m=f(u),p={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:u}},g=S({slug:n,environment:r,resourceType:"backup-role",suffix:t}),y=f(g),h={Type:"AWS::IAM::Role",Properties:{RoleName:g,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"]}},b=S({slug:n,environment:r,resourceType:"backup-plan",suffix:t}),v=f(b),T={DeleteAfterDays:s};if(l&&l<s)T.MoveToColdStorageAfterDays=l;let A={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:b,BackupPlanRule:[{RuleName:`${t}-daily-backup`,TargetBackupVault:C.Ref(m),ScheduleExpression:a,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:T,EnableContinuousBackup:c}]}}},R=S({slug:n,environment:r,resourceType:"backup-selection",suffix:t}),P=f(R),E=i.map((I)=>C.GetAtt(I,"Arn")),w={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:C.Ref(v),BackupSelection:{SelectionName:R,IamRoleArn:C.GetAtt(y,"Arn"),Resources:E}}};return{vault:p,plan:A,selection:w,role:h,vaultLogicalId:m,planLogicalId:v,selectionLogicalId:P,roleLogicalId:y}}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(e){let{slug:t,environment:n,sourceDomain:r,targetDomain:i,protocol:s="https"}=e,a=S({slug:t,environment:n,resourceType:"s3",suffix:"www-redirect"}),o=f(a),c={Type:"AWS::S3::Bucket",Properties:{BucketName:r,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:i,Protocol:s}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},l={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:C.Ref(o),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[C.Join("",[C.GetAtt(o,"Arn"),"/*"])]}]}}};return{bucket:c,bucketPolicy:l,logicalId:o}}static createDocsBucket(e){let{slug:t,environment:n,domain:r}=e,i=r||S({slug:t,environment:n,resourceType:"s3",suffix:"docs"}),s=f(i);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:i,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:s}}static createEmailBucket(e){let{slug:t,environment:n}=e,r=S({slug:t,environment:n,resourceType:"s3",suffix:"email"}),i=f(r),s={Type:"AWS::S3::Bucket",Properties:{BucketName:r,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"}]}]}}},a={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:C.Ref(i),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:C.Join("",[C.GetAtt(i,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":C.Ref("AWS::AccountId")}}}]}}};return{bucket:s,bucketPolicy:a,logicalId:i}}static docsExist(e={}){let{projectRoot:t=process.cwd(),docsPaths:n=["docs","documentation","doc"]}=e;for(let r of n){let i=Ae(t,r);if(Ye(i)){let s=["dist","build",".bunpress/dist","_site","out","public"];for(let a of s){let o=Ae(i,a);if(Ye(o))try{if(la(o).length>0)return{exists:!0,path:i,hasDistFolder:!0,distPath:o}}catch{}}return{exists:!0,path:i,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(e){let t=Ie.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!t.exists)return{bucket:null,logicalId:null,docsInfo:t};let n=Ie.createDocsBucket({slug:e.slug,environment:e.environment,domain:e.domain});return{bucket:n.bucket,bucketPolicy:n.bucketPolicy,logicalId:n.logicalId,docsInfo:t}}static createPrivateBucket(e){let{slug:t,environment:n,enableVersioning:r=!0,retentionDays:i,encryptionKeyArn:s}=e,a=S({slug:t,environment:n,resourceType:"s3",suffix:"private"}),o=f(a);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:a,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:s?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:s}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:r?{Status:"Enabled"}:void 0,LifecycleConfiguration:i?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:i}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:o}}static checkSourcePaths(e={}){let{projectRoot:t=process.cwd(),paths:n={}}=e,r=n.web||"views/web/dist",i=n.docs||"docs/dist",s=n.private||"private";return{web:{exists:Ye(Ae(t,r)),path:Ae(t,r)},docs:{exists:Ye(Ae(t,i)),path:Ae(t,i)},private:{exists:Ye(Ae(t,s)),path:Ae(t,s)}}}static createDeploymentBuckets(e){let{slug:t,environment:n,domain:r,projectRoot:i,paths:s}=e,a=Ie.checkSourcePaths({projectRoot:i,paths:s}),o={},c={web:!1,docs:!1,private:!1},l=Ie.createBucket({name:"web",slug:t,environment:n,public:!1,versioning:!1,encryption:!0});if(o[l.logicalId]=l.bucket,c.web=!0,a.docs.exists){let u=Ie.createDocsBucket({slug:t,environment:n,domain:r?`docs.${r}`:void 0});if(o[u.logicalId]=u.bucket,u.bucketPolicy)o[`${u.logicalId}Policy`]=u.bucketPolicy;c.docs=!0}if(a.private.exists){let u=Ie.createPrivateBucket({slug:t,environment:n,enableVersioning:!0});o[u.logicalId]=u.bucket,c.private=!0}return{resources:o,created:c,sourcePaths:a}}}class pe{static createRepository(e){let{name:t,slug:n,environment:r,scanOnPush:i=!0,imageMutability:s="MUTABLE",encryption:a="AES256",kmsKey:o,lifecyclePolicy:c,tags:l}=e,u=S({slug:n,environment:r,resourceType:"ecr",suffix:t}),m=f(u),p={Type:"AWS::ECR::Repository",Properties:{RepositoryName:u,ImageTagMutability:s,ImageScanningConfiguration:{ScanOnPush:i},EncryptionConfiguration:{EncryptionType:a,...o&&a==="KMS"?{KmsKey:o}:{}}}};if(c)p.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(pe.generateLifecyclePolicy(c))};if(l)p.Properties.Tags=Object.entries(l).map(([g,y])=>({Key:g,Value:y}));return{repository:p,logicalId:m}}static generateLifecyclePolicy(e){let t=[];if(e.untaggedImageExpireDays!==void 0)t.push({rulePriority:1,description:"Delete untagged images",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:e.untaggedImageExpireDays,countUnit:"days"},action:{type:"expire"}});if(e.maxImageCount!==void 0)t.push({rulePriority:t.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount},action:{type:"expire"}});if(e.maxImageAgeDays!==void 0)t.push({rulePriority:t.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:t}}static LifecyclePolicies={production:{maxImageCount:10,untaggedImageExpireDays:7},development:{maxImageCount:5,untaggedImageExpireDays:3},minimal:{maxImageCount:3,untaggedImageExpireDays:1},archive:{maxImageCount:50,untaggedImageExpireDays:30}};static enableImmutableTags(e){if(!e.Properties)e.Properties={};return e.Properties.ImageTagMutability="IMMUTABLE",e}static enableScanOnPush(e){if(!e.Properties)e.Properties={};return e.Properties.ImageScanningConfiguration={ScanOnPush:!0},e}static setLifecyclePolicy(e,t){if(!e.Properties)e.Properties={};return e.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(pe.generateLifecyclePolicy(t))},e}static addCrossAccountAccess(e,t){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:t.map((n)=>`arn:aws:iam::${n}:root`)},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]},e}static addLambdaAccess(e){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"LambdaECRImageRetrievalPolicy",Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]},e}static generateBunDockerfile(e){let{baseImage:t="oven/bun:1-debian",serverPath:n,port:r=3000,additionalDirs:i=[],healthCheckEndpoint:s="/health",nodeCompatible:a=!1,envVars:o={},buildCommands:c=[],runCommand:l}=e,u=["app","config",...i],m=l||`bun run ${n}`,p=`# Multi-stage build for Bun application
23
+ `)}import{existsSync as Ze,readdirSync as la}from"node:fs";import{join as ve}from"node:path";class De{static createBucket(e){let{name:t,bucketName:n,slug:r,environment:i,public:s=!1,versioning:a=!1,website:o=!1,encryption:c=!0,intelligentTiering:l=!1,cors:u,lifecycleRules:m}=e,p=n??S({slug:r,environment:i,resourceType:"s3",suffix:t}),g=f(p),y={Type:"AWS::S3::Bucket",Properties:{BucketName:p}};if(c)y.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(a)y.Properties.VersioningConfiguration={Status:"Enabled"};if(o)y.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!s)y.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(u&&u.length>0)y.Properties.CorsConfiguration={CorsRules:u.map((b)=>({AllowedOrigins:b.allowedOrigins,AllowedMethods:b.allowedMethods,AllowedHeaders:b.allowedHeaders,MaxAge:b.maxAge}))};if(m&&m.length>0)y.Properties.LifecycleConfiguration={Rules:m.map((b)=>({Id:b.id,Status:b.enabled?"Enabled":"Disabled",ExpirationInDays:b.expirationDays,Transitions:b.transitions?.map((C)=>({TransitionInDays:C.days,StorageClass:C.storageClass}))}))};if(l&&m){let b={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!y.Properties.LifecycleConfiguration)y.Properties.LifecycleConfiguration={Rules:[]};y.Properties.LifecycleConfiguration.Rules.push({Id:b.id,Status:"Enabled",Transitions:b.transitions?.map((C)=>({TransitionInDays:C.days,StorageClass:C.storageClass}))})}let h;if(s)h={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:v.Ref(g),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[v.Join("",[v.GetAtt(g,"Arn"),"/*"])]}]}}};return{bucket:y,bucketPolicy:h,logicalId:g}}static enableVersioning(e){if(!e.Properties)e.Properties={};return e.Properties.VersioningConfiguration={Status:"Enabled"},e}static enableWebsiteHosting(e,t="index.html",n="error.html"){if(!e.Properties)e.Properties={};return e.Properties.WebsiteConfiguration={IndexDocument:t,ErrorDocument:n},e}static setLifecycleRules(e,t){if(!e.Properties)e.Properties={};return e.Properties.LifecycleConfiguration={Rules:t.map((n)=>({Id:n.id,Status:n.enabled?"Enabled":"Disabled",ExpirationInDays:n.expirationDays,Transitions:n.transitions?.map((r)=>({TransitionInDays:r.days,StorageClass:r.storageClass}))}))},e}static enableIntelligentTiering(e){if(!e.Properties)e.Properties={};if(!e.Properties.LifecycleConfiguration)e.Properties.LifecycleConfiguration={Rules:[]};return e.Properties.LifecycleConfiguration.Rules.push({Id:"IntelligentTieringRule",Status:"Enabled",Transitions:[{TransitionInDays:0,StorageClass:"INTELLIGENT_TIERING"}]}),e}static addLambdaNotification(e,t){if(!e.Properties)e.Properties={};if(!e.Properties.NotificationConfiguration)e.Properties.NotificationConfiguration={};if(!e.Properties.NotificationConfiguration.LambdaConfigurations)e.Properties.NotificationConfiguration.LambdaConfigurations=[];let n={Event:t.events[0],Function:t.functionArn};if(t.filter)n.Filter={S3Key:{Rules:[...t.filter.prefix?[{Name:"prefix",Value:t.filter.prefix}]:[],...t.filter.suffix?[{Name:"suffix",Value:t.filter.suffix}]:[]]}};for(let r of t.events){let i={...n,Event:r};e.Properties.NotificationConfiguration.LambdaConfigurations.push(i)}return e}static Notifications={onObjectCreated:(e)=>({functionArn:e,events:["s3:ObjectCreated:*"]}),onObjectRemoved:(e)=>({functionArn:e,events:["s3:ObjectRemoved:*"]}),onImageUpload:(e,t)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:t,suffix:".jpg"}}),onFileType:(e,t,n)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:n,suffix:t}}),onFolderUpload:(e,t)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:t.endsWith("/")?t:`${t}/`}})};static createBackupPlan(e){let{name:t,slug:n,environment:r,bucketLogicalIds:i,retentionDays:s,schedule:a="cron(0 5 * * ? *)",vaultName:o,enableContinuousBackup:c=!1,moveToColdStorageAfterDays:l}=e,u=o||S({slug:n,environment:r,resourceType:"backup-vault",suffix:t}),m=f(u),p={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:u}},g=S({slug:n,environment:r,resourceType:"backup-role",suffix:t}),y=f(g),h={Type:"AWS::IAM::Role",Properties:{RoleName:g,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"]}},b=S({slug:n,environment:r,resourceType:"backup-plan",suffix:t}),C=f(b),T={DeleteAfterDays:s};if(l&&l<s)T.MoveToColdStorageAfterDays=l;let A={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:b,BackupPlanRule:[{RuleName:`${t}-daily-backup`,TargetBackupVault:v.Ref(m),ScheduleExpression:a,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:T,EnableContinuousBackup:c}]}}},R=S({slug:n,environment:r,resourceType:"backup-selection",suffix:t}),P=f(R),E=i.map((I)=>v.GetAtt(I,"Arn")),w={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:v.Ref(C),BackupSelection:{SelectionName:R,IamRoleArn:v.GetAtt(y,"Arn"),Resources:E}}};return{vault:p,plan:A,selection:w,role:h,vaultLogicalId:m,planLogicalId:C,selectionLogicalId:P,roleLogicalId:y}}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(e){let{slug:t,environment:n,sourceDomain:r,targetDomain:i,protocol:s="https"}=e,a=S({slug:t,environment:n,resourceType:"s3",suffix:"www-redirect"}),o=f(a),c={Type:"AWS::S3::Bucket",Properties:{BucketName:r,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:i,Protocol:s}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},l={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:v.Ref(o),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[v.Join("",[v.GetAtt(o,"Arn"),"/*"])]}]}}};return{bucket:c,bucketPolicy:l,logicalId:o}}static createDocsBucket(e){let{slug:t,environment:n,domain:r}=e,i=r||S({slug:t,environment:n,resourceType:"s3",suffix:"docs"}),s=f(i);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:i,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:s}}static createEmailBucket(e){let{slug:t,environment:n}=e,r=S({slug:t,environment:n,resourceType:"s3",suffix:"email"}),i=f(r),s={Type:"AWS::S3::Bucket",Properties:{BucketName:r,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"}]}]}}},a={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:v.Ref(i),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:v.Join("",[v.GetAtt(i,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":v.Ref("AWS::AccountId")}}}]}}};return{bucket:s,bucketPolicy:a,logicalId:i}}static docsExist(e={}){let{projectRoot:t=process.cwd(),docsPaths:n=["docs","documentation","doc"]}=e;for(let r of n){let i=ve(t,r);if(Ze(i)){let s=["dist","build",".bunpress/dist","_site","out","public"];for(let a of s){let o=ve(i,a);if(Ze(o))try{if(la(o).length>0)return{exists:!0,path:i,hasDistFolder:!0,distPath:o}}catch{}}return{exists:!0,path:i,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(e){let t=De.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!t.exists)return{bucket:null,logicalId:null,docsInfo:t};let n=De.createDocsBucket({slug:e.slug,environment:e.environment,domain:e.domain});return{bucket:n.bucket,bucketPolicy:n.bucketPolicy,logicalId:n.logicalId,docsInfo:t}}static createPrivateBucket(e){let{slug:t,environment:n,enableVersioning:r=!0,retentionDays:i,encryptionKeyArn:s}=e,a=S({slug:t,environment:n,resourceType:"s3",suffix:"private"}),o=f(a);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:a,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:s?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:s}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:r?{Status:"Enabled"}:void 0,LifecycleConfiguration:i?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:i}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:o}}static checkSourcePaths(e={}){let{projectRoot:t=process.cwd(),paths:n={}}=e,r=n.web||"views/web/dist",i=n.docs||"docs/dist",s=n.private||"private";return{web:{exists:Ze(ve(t,r)),path:ve(t,r)},docs:{exists:Ze(ve(t,i)),path:ve(t,i)},private:{exists:Ze(ve(t,s)),path:ve(t,s)}}}static createDeploymentBuckets(e){let{slug:t,environment:n,domain:r,projectRoot:i,paths:s}=e,a=De.checkSourcePaths({projectRoot:i,paths:s}),o={},c={web:!1,docs:!1,private:!1},l=De.createBucket({name:"web",slug:t,environment:n,public:!1,versioning:!1,encryption:!0});if(o[l.logicalId]=l.bucket,c.web=!0,a.docs.exists){let u=De.createDocsBucket({slug:t,environment:n,domain:r?`docs.${r}`:void 0});if(o[u.logicalId]=u.bucket,u.bucketPolicy)o[`${u.logicalId}Policy`]=u.bucketPolicy;c.docs=!0}if(a.private.exists){let u=De.createPrivateBucket({slug:t,environment:n,enableVersioning:!0});o[u.logicalId]=u.bucket,c.private=!0}return{resources:o,created:c,sourcePaths:a}}}class ye{static createRepository(e){let{name:t,slug:n,environment:r,scanOnPush:i=!0,imageMutability:s="MUTABLE",encryption:a="AES256",kmsKey:o,lifecyclePolicy:c,tags:l}=e,u=S({slug:n,environment:r,resourceType:"ecr",suffix:t}),m=f(u),p={Type:"AWS::ECR::Repository",Properties:{RepositoryName:u,ImageTagMutability:s,ImageScanningConfiguration:{ScanOnPush:i},EncryptionConfiguration:{EncryptionType:a,...o&&a==="KMS"?{KmsKey:o}:{}}}};if(c)p.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(ye.generateLifecyclePolicy(c))};if(l)p.Properties.Tags=Object.entries(l).map(([g,y])=>({Key:g,Value:y}));return{repository:p,logicalId:m}}static generateLifecyclePolicy(e){let t=[];if(e.untaggedImageExpireDays!==void 0)t.push({rulePriority:1,description:"Delete untagged images",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:e.untaggedImageExpireDays,countUnit:"days"},action:{type:"expire"}});if(e.maxImageCount!==void 0)t.push({rulePriority:t.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount},action:{type:"expire"}});if(e.maxImageAgeDays!==void 0)t.push({rulePriority:t.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:t}}static LifecyclePolicies={production:{maxImageCount:10,untaggedImageExpireDays:7},development:{maxImageCount:5,untaggedImageExpireDays:3},minimal:{maxImageCount:3,untaggedImageExpireDays:1},archive:{maxImageCount:50,untaggedImageExpireDays:30}};static enableImmutableTags(e){if(!e.Properties)e.Properties={};return e.Properties.ImageTagMutability="IMMUTABLE",e}static enableScanOnPush(e){if(!e.Properties)e.Properties={};return e.Properties.ImageScanningConfiguration={ScanOnPush:!0},e}static setLifecyclePolicy(e,t){if(!e.Properties)e.Properties={};return e.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(ye.generateLifecyclePolicy(t))},e}static addCrossAccountAccess(e,t){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:t.map((n)=>`arn:aws:iam::${n}:root`)},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]},e}static addLambdaAccess(e){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"LambdaECRImageRetrievalPolicy",Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]},e}static generateBunDockerfile(e){let{baseImage:t="oven/bun:1-debian",serverPath:n,port:r=3000,additionalDirs:i=[],healthCheckEndpoint:s="/health",nodeCompatible:a=!1,envVars:o={},buildCommands:c=[],runCommand:l}=e,u=["app","config",...i],m=l||`bun run ${n}`,p=`# Multi-stage build for Bun application
24
24
  # Generated by ts-cloud
25
25
 
26
26
  # Builder stage
@@ -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", "${n}"]
77
- `,p}static generateDockerBuildCommands(e){let{repositoryUri:t,tag:n="latest",dockerfilePath:r="Dockerfile",context:i=".",additionalTags:s=[],buildArgs:a={},platform:o="linux/amd64",noCache:c=!1}=e,l=`${t}:${n}`,u=[n,...s],m=`docker build -f ${r} -t ${l}`;if(o)m+=` --platform ${o}`;if(c)m+=" --no-cache";for(let[y,h]of Object.entries(a))m+=` --build-arg ${y}=${h}`;m+=` ${i}`;let p=u.slice(1).map((y)=>`docker tag ${l} ${t}:${y}`),g=u.map((y)=>`docker push ${t}:${y}`);return{build:m,tag:p,push:g,all:[m,...p,...g]}}static generateEcrLoginCommand(e,t){return`aws ecr get-login-password --region ${e} | docker login --username AWS --password-stdin ${t}.dkr.ecr.${e}.amazonaws.com`}static buildRepositoryUri(e){return`${e.accountId}.dkr.ecr.${e.region}.amazonaws.com/${e.repositoryName}`}static generateImageTags(e){let t=["latest"];if(e.version){t.push(e.version);let n=e.version.split(".");if(n.length>=2)t.push(`${n[0]}.${n[1]}`);if(n.length>=1)t.push(n[0])}if(e.gitSha)t.push(e.gitSha.substring(0,7)),t.push(e.gitSha);if(e.gitBranch){let n=e.gitBranch.replace(/[^a-zA-Z0-9.-]/g,"-").replace(/^-+|-+$/g,"");t.push(n)}if(e.environment)t.push(e.environment);if(e.timestamp){let n=new Date().toISOString().replace(/[:.]/g,"-").substring(0,19);t.push(n)}return[...new Set(t)]}static DeploymentWorkflow={generateDeployScript:(e)=>{let t=pe.buildRepositoryUri({accountId:e.accountId,region:e.region,repositoryName:e.repositoryName}),n=e.tags||["latest"],r=n[0];return`#!/bin/bash
77
+ `,p}static generateDockerBuildCommands(e){let{repositoryUri:t,tag:n="latest",dockerfilePath:r="Dockerfile",context:i=".",additionalTags:s=[],buildArgs:a={},platform:o="linux/amd64",noCache:c=!1}=e,l=`${t}:${n}`,u=[n,...s],m=`docker build -f ${r} -t ${l}`;if(o)m+=` --platform ${o}`;if(c)m+=" --no-cache";for(let[y,h]of Object.entries(a))m+=` --build-arg ${y}=${h}`;m+=` ${i}`;let p=u.slice(1).map((y)=>`docker tag ${l} ${t}:${y}`),g=u.map((y)=>`docker push ${t}:${y}`);return{build:m,tag:p,push:g,all:[m,...p,...g]}}static generateEcrLoginCommand(e,t){return`aws ecr get-login-password --region ${e} | docker login --username AWS --password-stdin ${t}.dkr.ecr.${e}.amazonaws.com`}static buildRepositoryUri(e){return`${e.accountId}.dkr.ecr.${e.region}.amazonaws.com/${e.repositoryName}`}static generateImageTags(e){let t=["latest"];if(e.version){t.push(e.version);let n=e.version.split(".");if(n.length>=2)t.push(`${n[0]}.${n[1]}`);if(n.length>=1)t.push(n[0])}if(e.gitSha)t.push(e.gitSha.substring(0,7)),t.push(e.gitSha);if(e.gitBranch){let n=e.gitBranch.replace(/[^a-zA-Z0-9.-]/g,"-").replace(/^-+|-+$/g,"");t.push(n)}if(e.environment)t.push(e.environment);if(e.timestamp){let n=new Date().toISOString().replace(/[:.]/g,"-").substring(0,19);t.push(n)}return[...new Set(t)]}static DeploymentWorkflow={generateDeployScript:(e)=>{let t=ye.buildRepositoryUri({accountId:e.accountId,region:e.region,repositoryName:e.repositoryName}),n=e.tags||["latest"],r=n[0];return`#!/bin/bash
78
78
  set -e
79
79
 
80
80
  # Configuration
@@ -85,7 +85,7 @@ IMAGE_URI="${t}"
85
85
  DOCKERFILE="${e.dockerfilePath||"Dockerfile"}"
86
86
 
87
87
  echo "=== ECR Login ==="
88
- ${pe.generateEcrLoginCommand(e.region,e.accountId)}
88
+ ${ye.generateEcrLoginCommand(e.region,e.accountId)}
89
89
 
90
90
  echo "=== Building Image ==="
91
91
  docker build -f $DOCKERFILE -t $IMAGE_URI:${r} --platform linux/amd64 .
@@ -103,7 +103,7 @@ echo "Image: $IMAGE_URI:${r}"
103
103
  docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
104
104
  docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest`},...e.ecsCluster&&e.ecsService?[{name:"Deploy to ECS",run:`aws ecs update-service --cluster ${e.ecsCluster} --service ${e.ecsService} --force-new-deployment`}]:[]]}}};return`# Generated by ts-cloud
105
105
  ${JSON.stringify(t,null,2).replace(/"/g,"").replace(/,\n/g,`
106
- `)}`}};static DockerfileTemplates={bunServer:(e,t=3000)=>pe.generateBunDockerfile({serverPath:e,port:t}),bunWithBuild:(e,t,n=3000)=>pe.generateBunDockerfile({serverPath:e,port:n,buildCommands:[t]}),bunFullStack:(e,t=3000)=>pe.generateBunDockerfile({serverPath:e,port:t,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,t=3000)=>pe.generateBunDockerfile({serverPath:e,port:t,healthCheckEndpoint:"/api/health"})}}var Vt=[400,403,404,416,429,500,502,503,504],tr=[500,502,503,504],nr=["GET","HEAD","OPTIONS"],ed="-failover-group",rr=["default","media-quality-based"],ir={min:1,max:3},sr={min:1,max:10};function ft(e){if(e===void 0)return[...tr];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${Vt.join(", ")}). Omit it to use the default ${tr.join(", ")}.`);let t=e.filter((n)=>!Vt.includes(n));if(t.length>0)throw Error(`CloudFront origin failover: ${t.join(", ")} ${t.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${Vt.join(", ")}.`);return[...new Set(e)].sort((n,r)=>n-r)}function Ut(e){let{primaryOriginId:t,secondaryOriginId:n}=e;if(!t||!n)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(t===n)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${t}")`);let r=ft(e.statusCodes);return ar(e.selectionCriteria),{Id:e.groupId??`${t}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:r.length,Items:r}},Members:{Quantity:2,Items:[{OriginId:t},{OriginId:n}]},...e.selectionCriteria?{SelectionCriteria:e.selectionCriteria}:{}}}function ar(e,t="the origin group"){if(e===void 0)return;if(!rr.includes(e))throw Error(`CloudFront origin failover: ${t} has selection criteria ${JSON.stringify(e)}. Allowed: ${rr.join(", ")}.`)}function yt(e,t,n){if(typeof e!=="number"||!Number.isInteger(e)||e<t.min||e>t.max)throw Error(`CloudFront origin: ${n} must be a whole number from ${t.min} to ${t.max}, got ${JSON.stringify(e)}.`)}function Be(e,t="the origin"){let n={};if(e?.connectionAttempts!==void 0)yt(e.connectionAttempts,ir,`${t} connectionAttempts`),n.ConnectionAttempts=e.connectionAttempts;if(e?.connectionTimeout!==void 0)yt(e.connectionTimeout,sr,`${t} connectionTimeout (seconds)`),n.ConnectionTimeout=e.connectionTimeout;return n}function td(e){return{Quantity:1,Items:[Ut(e)]}}function Ht(e,t="the cache behavior"){let r=(Array.isArray(e)?e:e?.Items??[]).filter((i)=>!nr.includes(i.toUpperCase()));if(r.length>0)throw Error(`CloudFront origin failover: ${t} allows ${r.join(", ")}, but a cache behavior that targets an origin group may only allow ${nr.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function or(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}function Ze(e){if(!e)return[];if(Array.isArray(e))return e;return e.Items??[]}function ge(e){return typeof e==="string"?e:void 0}var ua=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function cr(e,t="the distribution"){let n=Ze(e.Origins),r=new Set(n.map((u)=>ge(u.Id)).filter((u)=>!!u)),i=new Map(n.map((u)=>[ge(u.Id)??"",u.DomainName])),s=n.some((u)=>ge(u.Id)===void 0);for(let u of n){let m=ge(u.Id)??"(unnamed origin)";if(u.ConnectionAttempts!==void 0)yt(u.ConnectionAttempts,ir,`${t} origin "${m}" ConnectionAttempts`);if(u.ConnectionTimeout!==void 0)yt(u.ConnectionTimeout,sr,`${t} origin "${m}" ConnectionTimeout (seconds)`)}let a=e.OriginGroups,o=Ze(a);if(a&&!Array.isArray(a)&&a.Quantity!==void 0&&a.Quantity!==o.length)throw Error(`CloudFront origin failover: ${t} OriginGroups.Quantity is ${a.Quantity} but it lists ${o.length} group(s).`);let c=new Set;for(let u of o){let m=ge(u.Id);if(u.Id===void 0||u.Id==="")throw Error(`CloudFront origin failover: ${t} has an origin group without an Id.`);let p=`${t} origin group "${m??"(intrinsic id)"}"`;if(m){if(c.has(m))throw Error(`CloudFront origin failover: ${t} declares origin group "${m}" twice.`);if(r.has(m))throw Error(`CloudFront origin failover: ${p} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);c.add(m)}let g=u.Members,y=Ze(g);if(y.length!==2||g?.Quantity!==void 0&&g.Quantity!==y.length)throw Error(`CloudFront origin failover: ${p} must have exactly 2 members (a primary and a secondary), it has ${y.length}${g?.Quantity!==void 0&&g.Quantity!==y.length?` with Quantity ${g.Quantity}`:""}.`);let h=y.map((T)=>ge(T.OriginId));for(let T of h)if(T&&!r.has(T)&&!s)throw Error(`CloudFront origin failover: ${p} lists member "${T}", which is not an origin of this distribution. Origins: ${[...r].join(", ")||"(none)"}.`);if(h[0]&&h[0]===h[1])throw Error(`CloudFront origin failover: ${p} lists "${h[0]}" as both primary and secondary.`);let b=u.FailoverCriteria?.StatusCodes,v=Ze(b);if(ft(v),b?.Quantity!==void 0&&b.Quantity!==v.length)throw Error(`CloudFront origin failover: ${p} FailoverCriteria.StatusCodes.Quantity is ${b.Quantity} but it lists ${v.length} code(s).`);if(ar(u.SelectionCriteria,p),u.SelectionCriteria==="media-quality-based")for(let T of h){let A=T?ge(i.get(T)):void 0;if(A&&!ua.test(A))throw Error(`CloudFront origin failover: ${p} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${T}" is ${A}. Use 'default'.`)}}let l=[];if(e.DefaultCacheBehavior)l.push({behavior:e.DefaultCacheBehavior,name:"the default cache behavior"});for(let u of Ze(e.CacheBehaviors))l.push({behavior:u,name:`the cache behavior for ${JSON.stringify(u.PathPattern)}`});for(let{behavior:u,name:m}of l){let p=ge(u.TargetOriginId);if(!p)continue;if(c.has(p))Ht(u.AllowedMethods??["GET","HEAD"],`${m} of ${t} (origin group "${p}")`);else if(!r.has(p)&&!s&&o.every((g)=>ge(g.Id)!==void 0))throw Error(`CloudFront: ${m} of ${t} targets "${p}", which is neither an origin nor an origin group of this distribution.`)}}class ie{static createDistribution(e){let{slug:t,environment:n,origin:r,customDomain:i,certificateArn:s,errorPages:a,cachePolicy:o,edgeFunctions:c,http3:l=!1,comment:u,failoverOrigin:m}=e,p=S({slug:t,environment:n,resourceType:"cdn"}),g=f(p),y={Id:"DefaultOrigin",DomainName:r.domainName,OriginPath:r.originPath||"",...Be(r,"the CDN origin")},h;if(r.type==="s3"){let v=`${g}OAC`;h={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${p}-oac`,Description:`Origin Access Control for ${p}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},y.OriginAccessControlId=C.Ref(v)}else if(r.type==="alb"||r.type==="custom")y.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let b={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:u||`CDN for ${p}`,DefaultRootObject:"index.html",Origins:[y],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:l?"http2and3":"http2"}}};if(i&&s)b.Properties.DistributionConfig.Aliases=[i],b.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(a&&a.length>0)b.Properties.DistributionConfig.CustomErrorResponses=a.map((v)=>({ErrorCode:v.errorCode,ResponseCode:v.responseCode,ResponsePagePath:v.responsePagePath}));if(c&&c.length>0)b.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=c.map((v)=>({EventType:v.event,LambdaFunctionARN:v.functionArn}));if(m)ie.addOriginFailover(b,m);return{distribution:b,originAccessControl:h,logicalId:g}}static addOriginFailover(e,t){let n=e.Properties.DistributionConfig,r=n.DefaultCacheBehavior,i=r.TargetOriginId,s=t.id??"FailoverOrigin";if(n.OriginGroups&&n.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(Ht(r.AllowedMethods??["GET","HEAD"],"the default cache behavior"),n.Origins.some((u)=>u.Id===s))throw Error(`CloudFront origin failover: an origin with id "${s}" already exists`);let a=Ut({primaryOriginId:i,secondaryOriginId:s,statusCodes:t.statusCodes,selectionCriteria:t.selectionCriteria}),o=t.type??(or(t.domainName)?"s3":"custom"),c={Id:s,DomainName:t.domainName,OriginPath:t.originPath||"",...Be(t,"the failover origin")},l=Be(t.primary,"the primary origin");if(Object.keys(l).length>0){let u=n.Origins.find((m)=>m.Id===i);if(u)Object.assign(u,l)}if(o==="s3"){let u=n.Origins.find((m)=>m.Id===i);if(c.S3OriginConfig={OriginAccessIdentity:""},u?.OriginAccessControlId)c.OriginAccessControlId=u.OriginAccessControlId}else c.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return n.Origins.push(c),n.OriginGroups={Quantity:1,Items:[a]},r.TargetOriginId=a.Id,cr(n),e}static setCustomDomain(e,t,n){return e.Properties.DistributionConfig.Aliases=[t],e.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:n,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},e}static setErrorPages(e,t){return e.Properties.DistributionConfig.CustomErrorResponses=t.map((n)=>({ErrorCode:n.errorCode,ResponseCode:n.responseCode,ResponsePagePath:n.responsePagePath})),e}static enableHttp3(e){return e.Properties.DistributionConfig.HttpVersion="http2and3",e}static addEdgeFunction(e,t,n){if(!e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:t,LambdaFunctionARN:n}),e}static setCachePolicy(e,t){return e.Properties.DistributionConfig.Comment=`${e.Properties.DistributionConfig.Comment||""} (TTL: ${t.default||86400}s)`,e}static createSpaDistribution(e){return ie.createDistribution({...e,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(e){let{slug:t,environment:n}=e,r=S({slug:t,environment:n,resourceType:"edge-docs"}),i=f(r),s=f(`${r}-role`),a=f(`${r}-version`),o={Type:"AWS::IAM::Role",Properties:{RoleName:`${r}-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"]}},c=`
106
+ `)}`}};static DockerfileTemplates={bunServer:(e,t=3000)=>ye.generateBunDockerfile({serverPath:e,port:t}),bunWithBuild:(e,t,n=3000)=>ye.generateBunDockerfile({serverPath:e,port:n,buildCommands:[t]}),bunFullStack:(e,t=3000)=>ye.generateBunDockerfile({serverPath:e,port:t,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,t=3000)=>ye.generateBunDockerfile({serverPath:e,port:t,healthCheckEndpoint:"/api/health"})}}var Vt=[400,403,404,416,429,500,502,503,504],tr=[500,502,503,504],nr=["GET","HEAD","OPTIONS"],ed="-failover-group",rr=["default","media-quality-based"],ir={min:1,max:3},sr={min:1,max:10};function ht(e){if(e===void 0)return[...tr];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${Vt.join(", ")}). Omit it to use the default ${tr.join(", ")}.`);let t=e.filter((n)=>!Vt.includes(n));if(t.length>0)throw Error(`CloudFront origin failover: ${t.join(", ")} ${t.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${Vt.join(", ")}.`);return[...new Set(e)].sort((n,r)=>n-r)}function Ut(e){let{primaryOriginId:t,secondaryOriginId:n}=e;if(!t||!n)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(t===n)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${t}")`);let r=ht(e.statusCodes);return ar(e.selectionCriteria),{Id:e.groupId??`${t}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:r.length,Items:r}},Members:{Quantity:2,Items:[{OriginId:t},{OriginId:n}]},...e.selectionCriteria?{SelectionCriteria:e.selectionCriteria}:{}}}function ar(e,t="the origin group"){if(e===void 0)return;if(!rr.includes(e))throw Error(`CloudFront origin failover: ${t} has selection criteria ${JSON.stringify(e)}. Allowed: ${rr.join(", ")}.`)}function ft(e,t,n){if(typeof e!=="number"||!Number.isInteger(e)||e<t.min||e>t.max)throw Error(`CloudFront origin: ${n} must be a whole number from ${t.min} to ${t.max}, got ${JSON.stringify(e)}.`)}function Ge(e,t="the origin"){let n={};if(e?.connectionAttempts!==void 0)ft(e.connectionAttempts,ir,`${t} connectionAttempts`),n.ConnectionAttempts=e.connectionAttempts;if(e?.connectionTimeout!==void 0)ft(e.connectionTimeout,sr,`${t} connectionTimeout (seconds)`),n.ConnectionTimeout=e.connectionTimeout;return n}function td(e){return{Quantity:1,Items:[Ut(e)]}}function Ht(e,t="the cache behavior"){let r=(Array.isArray(e)?e:e?.Items??[]).filter((i)=>!nr.includes(i.toUpperCase()));if(r.length>0)throw Error(`CloudFront origin failover: ${t} allows ${r.join(", ")}, but a cache behavior that targets an origin group may only allow ${nr.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function or(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}function Xe(e){if(!e)return[];if(Array.isArray(e))return e;return e.Items??[]}function fe(e){return typeof e==="string"?e:void 0}var ua=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function cr(e,t="the distribution"){let n=Xe(e.Origins),r=new Set(n.map((u)=>fe(u.Id)).filter((u)=>!!u)),i=new Map(n.map((u)=>[fe(u.Id)??"",u.DomainName])),s=n.some((u)=>fe(u.Id)===void 0);for(let u of n){let m=fe(u.Id)??"(unnamed origin)";if(u.ConnectionAttempts!==void 0)ft(u.ConnectionAttempts,ir,`${t} origin "${m}" ConnectionAttempts`);if(u.ConnectionTimeout!==void 0)ft(u.ConnectionTimeout,sr,`${t} origin "${m}" ConnectionTimeout (seconds)`)}let a=e.OriginGroups,o=Xe(a);if(a&&!Array.isArray(a)&&a.Quantity!==void 0&&a.Quantity!==o.length)throw Error(`CloudFront origin failover: ${t} OriginGroups.Quantity is ${a.Quantity} but it lists ${o.length} group(s).`);let c=new Set;for(let u of o){let m=fe(u.Id);if(u.Id===void 0||u.Id==="")throw Error(`CloudFront origin failover: ${t} has an origin group without an Id.`);let p=`${t} origin group "${m??"(intrinsic id)"}"`;if(m){if(c.has(m))throw Error(`CloudFront origin failover: ${t} declares origin group "${m}" twice.`);if(r.has(m))throw Error(`CloudFront origin failover: ${p} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);c.add(m)}let g=u.Members,y=Xe(g);if(y.length!==2||g?.Quantity!==void 0&&g.Quantity!==y.length)throw Error(`CloudFront origin failover: ${p} must have exactly 2 members (a primary and a secondary), it has ${y.length}${g?.Quantity!==void 0&&g.Quantity!==y.length?` with Quantity ${g.Quantity}`:""}.`);let h=y.map((T)=>fe(T.OriginId));for(let T of h)if(T&&!r.has(T)&&!s)throw Error(`CloudFront origin failover: ${p} lists member "${T}", which is not an origin of this distribution. Origins: ${[...r].join(", ")||"(none)"}.`);if(h[0]&&h[0]===h[1])throw Error(`CloudFront origin failover: ${p} lists "${h[0]}" as both primary and secondary.`);let b=u.FailoverCriteria?.StatusCodes,C=Xe(b);if(ht(C),b?.Quantity!==void 0&&b.Quantity!==C.length)throw Error(`CloudFront origin failover: ${p} FailoverCriteria.StatusCodes.Quantity is ${b.Quantity} but it lists ${C.length} code(s).`);if(ar(u.SelectionCriteria,p),u.SelectionCriteria==="media-quality-based")for(let T of h){let A=T?fe(i.get(T)):void 0;if(A&&!ua.test(A))throw Error(`CloudFront origin failover: ${p} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${T}" is ${A}. Use 'default'.`)}}let l=[];if(e.DefaultCacheBehavior)l.push({behavior:e.DefaultCacheBehavior,name:"the default cache behavior"});for(let u of Xe(e.CacheBehaviors))l.push({behavior:u,name:`the cache behavior for ${JSON.stringify(u.PathPattern)}`});for(let{behavior:u,name:m}of l){let p=fe(u.TargetOriginId);if(!p)continue;if(c.has(p))Ht(u.AllowedMethods??["GET","HEAD"],`${m} of ${t} (origin group "${p}")`);else if(!r.has(p)&&!s&&o.every((g)=>fe(g.Id)!==void 0))throw Error(`CloudFront: ${m} of ${t} targets "${p}", which is neither an origin nor an origin group of this distribution.`)}}class se{static createDistribution(e){let{slug:t,environment:n,origin:r,customDomain:i,certificateArn:s,errorPages:a,cachePolicy:o,edgeFunctions:c,http3:l=!1,comment:u,failoverOrigin:m}=e,p=S({slug:t,environment:n,resourceType:"cdn"}),g=f(p),y={Id:"DefaultOrigin",DomainName:r.domainName,OriginPath:r.originPath||"",...Ge(r,"the CDN origin")},h;if(r.type==="s3"){let C=`${g}OAC`;h={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${p}-oac`,Description:`Origin Access Control for ${p}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},y.OriginAccessControlId=v.Ref(C)}else if(r.type==="alb"||r.type==="custom")y.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let b={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:u||`CDN for ${p}`,DefaultRootObject:"index.html",Origins:[y],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:l?"http2and3":"http2"}}};if(i&&s)b.Properties.DistributionConfig.Aliases=[i],b.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(a&&a.length>0)b.Properties.DistributionConfig.CustomErrorResponses=a.map((C)=>({ErrorCode:C.errorCode,ResponseCode:C.responseCode,ResponsePagePath:C.responsePagePath}));if(c&&c.length>0)b.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=c.map((C)=>({EventType:C.event,LambdaFunctionARN:C.functionArn}));if(m)se.addOriginFailover(b,m);return{distribution:b,originAccessControl:h,logicalId:g}}static addOriginFailover(e,t){let n=e.Properties.DistributionConfig,r=n.DefaultCacheBehavior,i=r.TargetOriginId,s=t.id??"FailoverOrigin";if(n.OriginGroups&&n.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(Ht(r.AllowedMethods??["GET","HEAD"],"the default cache behavior"),n.Origins.some((u)=>u.Id===s))throw Error(`CloudFront origin failover: an origin with id "${s}" already exists`);let a=Ut({primaryOriginId:i,secondaryOriginId:s,statusCodes:t.statusCodes,selectionCriteria:t.selectionCriteria}),o=t.type??(or(t.domainName)?"s3":"custom"),c={Id:s,DomainName:t.domainName,OriginPath:t.originPath||"",...Ge(t,"the failover origin")},l=Ge(t.primary,"the primary origin");if(Object.keys(l).length>0){let u=n.Origins.find((m)=>m.Id===i);if(u)Object.assign(u,l)}if(o==="s3"){let u=n.Origins.find((m)=>m.Id===i);if(c.S3OriginConfig={OriginAccessIdentity:""},u?.OriginAccessControlId)c.OriginAccessControlId=u.OriginAccessControlId}else c.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return n.Origins.push(c),n.OriginGroups={Quantity:1,Items:[a]},r.TargetOriginId=a.Id,cr(n),e}static setCustomDomain(e,t,n){return e.Properties.DistributionConfig.Aliases=[t],e.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:n,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},e}static setErrorPages(e,t){return e.Properties.DistributionConfig.CustomErrorResponses=t.map((n)=>({ErrorCode:n.errorCode,ResponseCode:n.responseCode,ResponsePagePath:n.responsePagePath})),e}static enableHttp3(e){return e.Properties.DistributionConfig.HttpVersion="http2and3",e}static addEdgeFunction(e,t,n){if(!e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:t,LambdaFunctionARN:n}),e}static setCachePolicy(e,t){return e.Properties.DistributionConfig.Comment=`${e.Properties.DistributionConfig.Comment||""} (TTL: ${t.default||86400}s)`,e}static createSpaDistribution(e){return se.createDistribution({...e,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(e){let{slug:t,environment:n}=e,r=S({slug:t,environment:n,resourceType:"edge-docs"}),i=f(r),s=f(`${r}-role`),a=f(`${r}-version`),o={Type:"AWS::IAM::Role",Properties:{RoleName:`${r}-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"]}},c=`
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:r,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:C.GetAtt(s,"Arn"),Code:{ZipFile:c},MemorySize:128,Timeout:5}},role:o,functionLogicalId:i,roleLogicalId:s,versionLogicalId:a}}static createDocsDistribution(e){let{slug:t,environment:n,origin:r,customDomain:i,certificateArn:s,lambdaEdgeFunctionArn:a}=e,o=ie.createDistribution({slug:t,environment:n,origin:r,customDomain:i,certificateArn:s,comment:`Docs CDN for ${t}`,errorPages:[{errorCode:404,responseCode:404,responsePagePath:"/404.html"},{errorCode:403,responseCode:403,responsePagePath:"/404.html"}]});if(a)ie.addEdgeFunction(o.distribution,"origin-request",a);return o.distribution.Properties.DistributionConfig.DefaultCacheBehavior.DefaultTTL=86400,o.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MaxTTL=604800,o.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MinTTL=0,o}static createApiDistribution(e){let{slug:t,environment:n,albDomainName:r,customDomain:i,certificateArn:s,pathPattern:a="/api/*",forwardHeaders:o=["Host","Origin","Authorization","Content-Type","Accept"],forwardCookies:c="all",whitelistedCookies:l,customOriginHeaders:u={}}=e,m=S({slug:t,environment:n,resourceType:"cdn-api"}),p=f(m),g=Object.entries(u).map(([v,T])=>({HeaderName:v,HeaderValue:T})),y={Id:"ALBOrigin",DomainName:r,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(g.length>0)y.OriginCustomHeaders=g;let h={Forward:c};if(c==="whitelist"&&l)h.WhitelistedNames=l;let b={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`API CDN for ${m}`,Origins:[y],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:o,Cookies:h}},PriceClass:"PriceClass_100",HttpVersion:"http2"}}};if(i&&s)b.Properties.DistributionConfig.Aliases=[i],b.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:b,logicalId:p}}static createMultiOriginDistribution(e){let{slug:t,environment:n,s3BucketDomainName:r,albDomainName:i,apiPathPattern:s="/api/*",customDomain:a,certificateArn:o,customOriginHeaders:c={}}=e,l=S({slug:t,environment:n,resourceType:"cdn"}),u=f(l),m=`${u}OAC`,p={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${l}-oac`,Description:`Origin Access Control for ${l}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},g=Object.entries(c).map(([v,T])=>({HeaderName:v,HeaderValue:T})),y={Id:"S3Origin",DomainName:r,OriginAccessControlId:C.Ref(m)},h={Id:"ALBOrigin",DomainName:i,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(g.length>0)h.OriginCustomHeaders=g;let b={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`Multi-origin CDN for ${l}`,DefaultRootObject:"index.html",Origins:[y,h],DefaultCacheBehavior:{TargetOriginId:"S3Origin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},CacheBehaviors:[{PathPattern:s,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(a&&o)b.Properties.DistributionConfig.Aliases=[a],b.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:o,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:b,originAccessControl:p,logicalId:u,oacLogicalId:m}}static addAlbOrigin(e,t){let{originId:n,domainName:r,pathPattern:i,customHeaders:s={},forwardHeaders:a=["Host","Origin","Authorization","Content-Type","Accept"],cacheTtl:o={default:0,max:0,min:0}}=t,c=Object.entries(s).map(([u,m])=>({HeaderName:u,HeaderValue:m})),l={Id:n,DomainName:r,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(c.length>0)l.OriginCustomHeaders=c;if(!e.Properties.DistributionConfig.Origins)e.Properties.DistributionConfig.Origins=[];if(e.Properties.DistributionConfig.Origins.push(l),!e.Properties.DistributionConfig.CacheBehaviors)e.Properties.DistributionConfig.CacheBehaviors=[];return e.Properties.DistributionConfig.CacheBehaviors.push({PathPattern:i,TargetOriginId:n,ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:o.default,MaxTTL:o.max,MinTTL:o.min,ForwardedValues:{QueryString:!0,Headers:a,Cookies:{Forward:"all"}}}),e}static addOriginHeader(e,t,n,r){let i=e.Properties.DistributionConfig.Origins?.find((s)=>s.Id===t);if(i){if(!i.OriginCustomHeaders)i.OriginCustomHeaders=[];i.OriginCustomHeaders.push({HeaderName:n,HeaderValue:r})}return e}static EdgeFunctionTemplates={docsOriginRequest:`
139
+ `.trim();return{lambdaFunction:{Type:"AWS::Lambda::Function",Properties:{FunctionName:r,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:v.GetAtt(s,"Arn"),Code:{ZipFile:c},MemorySize:128,Timeout:5}},role:o,functionLogicalId:i,roleLogicalId:s,versionLogicalId:a}}static createDocsDistribution(e){let{slug:t,environment:n,origin:r,customDomain:i,certificateArn:s,lambdaEdgeFunctionArn:a}=e,o=se.createDistribution({slug:t,environment:n,origin:r,customDomain:i,certificateArn:s,comment:`Docs CDN for ${t}`,errorPages:[{errorCode:404,responseCode:404,responsePagePath:"/404.html"},{errorCode:403,responseCode:403,responsePagePath:"/404.html"}]});if(a)se.addEdgeFunction(o.distribution,"origin-request",a);return o.distribution.Properties.DistributionConfig.DefaultCacheBehavior.DefaultTTL=86400,o.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MaxTTL=604800,o.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MinTTL=0,o}static createApiDistribution(e){let{slug:t,environment:n,albDomainName:r,customDomain:i,certificateArn:s,pathPattern:a="/api/*",forwardHeaders:o=["Host","Origin","Authorization","Content-Type","Accept"],forwardCookies:c="all",whitelistedCookies:l,customOriginHeaders:u={}}=e,m=S({slug:t,environment:n,resourceType:"cdn-api"}),p=f(m),g=Object.entries(u).map(([C,T])=>({HeaderName:C,HeaderValue:T})),y={Id:"ALBOrigin",DomainName:r,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(g.length>0)y.OriginCustomHeaders=g;let h={Forward:c};if(c==="whitelist"&&l)h.WhitelistedNames=l;let b={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`API CDN for ${m}`,Origins:[y],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:o,Cookies:h}},PriceClass:"PriceClass_100",HttpVersion:"http2"}}};if(i&&s)b.Properties.DistributionConfig.Aliases=[i],b.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:b,logicalId:p}}static createMultiOriginDistribution(e){let{slug:t,environment:n,s3BucketDomainName:r,albDomainName:i,apiPathPattern:s="/api/*",customDomain:a,certificateArn:o,customOriginHeaders:c={}}=e,l=S({slug:t,environment:n,resourceType:"cdn"}),u=f(l),m=`${u}OAC`,p={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${l}-oac`,Description:`Origin Access Control for ${l}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},g=Object.entries(c).map(([C,T])=>({HeaderName:C,HeaderValue:T})),y={Id:"S3Origin",DomainName:r,OriginAccessControlId:v.Ref(m)},h={Id:"ALBOrigin",DomainName:i,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(g.length>0)h.OriginCustomHeaders=g;let b={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`Multi-origin CDN for ${l}`,DefaultRootObject:"index.html",Origins:[y,h],DefaultCacheBehavior:{TargetOriginId:"S3Origin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},CacheBehaviors:[{PathPattern:s,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(a&&o)b.Properties.DistributionConfig.Aliases=[a],b.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:o,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:b,originAccessControl:p,logicalId:u,oacLogicalId:m}}static addAlbOrigin(e,t){let{originId:n,domainName:r,pathPattern:i,customHeaders:s={},forwardHeaders:a=["Host","Origin","Authorization","Content-Type","Accept"],cacheTtl:o={default:0,max:0,min:0}}=t,c=Object.entries(s).map(([u,m])=>({HeaderName:u,HeaderValue:m})),l={Id:n,DomainName:r,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(c.length>0)l.OriginCustomHeaders=c;if(!e.Properties.DistributionConfig.Origins)e.Properties.DistributionConfig.Origins=[];if(e.Properties.DistributionConfig.Origins.push(l),!e.Properties.DistributionConfig.CacheBehaviors)e.Properties.DistributionConfig.CacheBehaviors=[];return e.Properties.DistributionConfig.CacheBehaviors.push({PathPattern:i,TargetOriginId:n,ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:o.default,MaxTTL:o.max,MinTTL:o.min,ForwardedValues:{QueryString:!0,Headers:a,Cookies:{Forward:"all"}}}),e}static addOriginHeader(e,t,n,r){let i=e.Properties.DistributionConfig.Origins?.find((s)=>s.Id===t);if(i){if(!i.OriginCustomHeaders)i.OriginCustomHeaders=[];i.OriginCustomHeaders.push({HeaderName:n,HeaderValue:r})}return e}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:(e)=>{let{min:t=0,max:n=86400,default:r=86400}=e;return{MinTTL:t,MaxTTL:n,DefaultTTL:r}},cookies:(e,t)=>{let n={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&t)n.WhitelistedNames=t;return n},allowedMethods:(e)=>{let t={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return t[e]||t.GET_HEAD},cachedMethods:(e)=>{let t={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return t[e]||t.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:(e)=>{let{ttl:t={min:0,max:86400,default:86400},cookies:n="none",allowedCookies:r,allowedMethods:i="GET_HEAD",cachedMethods:s="GET_HEAD",compress:a=!0,forwardQueryString:o=!0,forwardHeaders:c=[]}=e;return{MinTTL:t.min,MaxTTL:t.max,DefaultTTL:t.default,Compress:a,AllowedMethods:ie.Config.allowedMethods(i),CachedMethods:ie.Config.cachedMethods(s),ForwardedValues:{QueryString:o,Headers:c,Cookies:ie.Config.cookies(n,r)}}}};static applyConfig(e,t){let n=e.Properties.DistributionConfig.DefaultCacheBehavior;if(t.ttl)n.MinTTL=t.ttl.min,n.MaxTTL=t.ttl.max,n.DefaultTTL=t.ttl.default;if(t.compress!==void 0)n.Compress=t.compress;if(t.allowedMethods)n.AllowedMethods=ie.Config.allowedMethods(t.allowedMethods);if(t.cachedMethods)n.CachedMethods=ie.Config.cachedMethods(t.cachedMethods);if(t.cookies){if(!n.ForwardedValues)n.ForwardedValues={QueryString:!0};n.ForwardedValues.Cookies=ie.Config.cookies(t.cookies,t.allowedCookies)}return e}}var da=[403,404,500,502,503,504],ma="TsCloud::StorageFailover",pa="AllowCloudFrontFailoverRead",ga=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,ya=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function cd(e){let{failover:t,primaryBucket:n,primaryRegion:r}=e,i=e.where??"storage failover";if(!t||typeof t!=="object")throw Error(`${i}.failover must be an object such as { region: 'us-west-2' }.`);if(!t.region||!ga.test(t.region))throw Error(`${i}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(t.region)}.`);if(t.region===r)throw Error(`${i}.failover.region is ${t.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let s=t.bucket??`${n}-${t.region}`;if(!ya.test(s)||s.includes("..")){let a=t.bucket===void 0&&s.length>63?` The default name (<primary bucket>-<region>) is ${s.length} characters; S3 allows 63. Set ${i}.failover.bucket.`:"";throw Error(`${i}.failover: "${s}" is not a valid S3 bucket name.${a}`)}if(s===n)throw Error(`${i}.failover.bucket must differ from the primary bucket "${n}".`);return{replicaBucket:s,replicaRegion:t.region,replicate:t.replicate!==!1,statusCodes:ft(t.statusCodes??da),primaryConnection:Be(t,`${i}.failover`)}}function ld(e,t){return`${e}.s3.${t}.amazonaws.com`}function ud(e){let t=`arn:aws:s3:::${e.primaryBucket}`,n=`arn:aws:s3:::${e.replicaBucket}`;return{Type:"AWS::IAM::Role",Properties:{...e.roleName?{RoleName:e.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:t},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${t}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${n}/*`}]}}]}}}function dd(e){return{Role:e.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${e.replicaBucket}`}}]}}function md(e){return{Sid:pa,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function pd(e){let n=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[ma];return Array.isArray(n)?n:[]}class Q{static createHostedZone(e){let{domain:t,slug:n,environment:r,comment:i}=e,s=S({slug:n,environment:r,resourceType:"hostedzone"}),a=f(`${s}-${t.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:t,HostedZoneConfig:{Comment:i||`Hosted zone for ${t}`}}},logicalId:a}}static createRecord(e){let{hostedZoneId:t,hostedZoneName:n,name:r,type:i,ttl:s,values:a,aliasTarget:o}=e,c=f(`record-${r.replace(/\./g,"")}-${i}`),l={Type:"AWS::Route53::RecordSet",Properties:{Name:r,Type:i}};if(t)l.Properties.HostedZoneId=t;else if(n)l.Properties.HostedZoneName=n;if(o)l.Properties.AliasTarget={DNSName:o.dnsName,HostedZoneId:o.hostedZoneId,EvaluateTargetHealth:o.evaluateTargetHealth??!1};else l.Properties.TTL=s||300,l.Properties.ResourceRecords=a||[];return{record:l,logicalId:c}}static createCloudFrontAlias(e,t,n){return Q.createRecord({hostedZoneId:n,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,t,n,r){return Q.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:n,evaluateTargetHealth:!0}})}static createCname(e,t,n,r=300){return Q.createRecord({hostedZoneId:n,name:e,type:"CNAME",ttl:r,values:[t]})}static createWwwRedirect(e,t){return Q.createRecord({hostedZoneId:t,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,t,n,r=300){return Q.createRecord({hostedZoneId:n,name:e,type:"MX",ttl:r,values:t.map((i)=>`${i.priority} ${i.server}`)})}static createTxtRecord(e,t,n,r=300){return Q.createRecord({hostedZoneId:n,name:e,type:"TXT",ttl:r,values:[`"${t}"`]})}static createSpfRecord(e,t,n){return Q.createTxtRecord(e,t,n)}static createDmarcRecord(e,t,n,r){let i=`v=DMARC1; p=${t}; rua=mailto:${n}`;return Q.createTxtRecord(`_dmarc.${e}`,i,r)}static createS3WebsiteAlias(e,t,n,r){return Q.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:n,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(e,t){return`${e}.s3-website-${t}.amazonaws.com`}static createStoreRecord(e,t,n){return Q.createCname(`store.${e}`,t,n)}static createApiRecord(e,t,n){return Q.createCname(`api.${e}`,t,n)}static createDocsRecord(e,t,n){return Q.createCname(`docs.${e}`,t,n)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class W{static createCertificate(e){let{domain:t,subdomains:n=[],slug:r,environment:i,validationMethod:s="DNS",hostedZoneId:a}=e,o=S({slug:r,environment:i,resourceType:"acm"}),c=f(`${o}-${t.replace(/\./g,"")}`),l=[t];for(let m of n)if(m==="*")l.push(`*.${t}`);else l.push(`${m}.${t}`);let u={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:t,SubjectAlternativeNames:l,ValidationMethod:s}};if(s==="DNS"&&a)u.Properties.DomainValidationOptions=l.map((m)=>({DomainName:m,HostedZoneId:a}));return{certificate:u,logicalId:c}}static createKmsKey(e){let{description:t,slug:n,environment:r,enableRotation:i=!0,multiRegion:s=!1}=e,a=S({slug:n,environment:r,resourceType:"kms"}),o=f(a),c={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:C.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:"*"}]},l={Type:"AWS::KMS::Key",Properties:{Description:t,Enabled:!0,EnableKeyRotation:i,KeyPolicy:c,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:s}},u=f(`${a}-alias`),m={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${n}-${r}`,TargetKeyId:C.Ref(o)}};return{key:l,alias:m,logicalId:o,aliasId:u}}static createFirewall(e){let{slug:t,environment:n,scope:r="CLOUDFRONT",defaultAction:i="allow"}=e,s=S({slug:t,environment:n,resourceType:"waf"}),a=f(s);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:s,Scope:r,DefaultAction:i==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${t} ${n}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-metric`}}},logicalId:a}}static setRateLimit(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{RateBasedStatement:{Limit:t.requestsPerWindow,AggregateKeyType:t.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static blockCountries(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{GeoMatchStatement:{CountryCodes:t.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static blockIpAddresses(e,t,n,r){let i=S({slug:n,environment:r,resourceType:"ipset"}),s=f(`${i}-${t.name}`),a={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${i}-${t.name}`,Scope:e.Properties.Scope,IPAddressVersion:t.ipVersion||"IPV4",Addresses:t.ipAddresses,Description:`Blocked IPs for ${t.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{IPSetReferenceStatement:{Arn:C.GetAtt(s,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),{webAcl:e,ipSet:a,ipSetLogicalId:s}}static addManagedRules(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];let n={ManagedRuleGroupStatement:{VendorName:t.vendorName,Name:t.ruleName}};if(t.excludedRules&&t.excludedRules.length>0)n.ManagedRuleGroupStatement.ExcludedRules=t.excludedRules.map((r)=>({Name:r}));return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:n,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}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(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];let n=t.paths.map((r)=>({SearchString:r,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{RateBasedStatement:{Limit:t.requestsPerWindow,AggregateKeyType:t.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:n.map((r)=>({ByteMatchStatement:r}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static setHeaderRateLimit(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];let n={RateBasedStatement:{Limit:t.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:t.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(t.headerValue)n.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:t.headerValue,FieldToMatch:{SingleHeader:{Name:t.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:n,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static protectLoginEndpoint(e,t){let{loginPaths:n,priority:r,requestsPerMinute:i=10}=t;return W.setPathRateLimit(e,{name:"LoginRateLimit",priority:r,requestsPerWindow:i*5,paths:n}),e}static protectApiEndpoints(e,t){let{apiPaths:n,priority:r,requestsPerMinute:i=100}=t;return W.setPathRateLimit(e,{name:"ApiRateLimit",priority:r,requestsPerWindow:i*5,paths:n}),e}static createProtectedFirewall(e){let{slug:t,environment:n,scope:r="CLOUDFRONT",enableBotControl:i=!1,enableRateLimiting:s=!0,rateLimitPerMinute:a=2000}=e,{webAcl:o,logicalId:c}=W.createFirewall({slug:t,environment:n,scope:r,defaultAction:"allow"}),l=0;if(o=W.addManagedRules(o,{name:"AWSIPReputationList",priority:l++,...W.ManagedRuleGroups.AmazonIpReputation}),o=W.addManagedRules(o,{name:"AWSAnonymousIPList",priority:l++,...W.ManagedRuleGroups.AnonymousIpList}),o=W.addManagedRules(o,{name:"AWSCoreRuleSet",priority:l++,...W.ManagedRuleGroups.CoreRuleSet}),o=W.addManagedRules(o,{name:"AWSKnownBadInputs",priority:l++,...W.ManagedRuleGroups.KnownBadInputs}),o=W.addManagedRules(o,{name:"AWSSQLi",priority:l++,...W.ManagedRuleGroups.SqlDatabase}),i)o=W.addManagedRules(o,{name:"AWSBotControl",priority:l++,...W.ManagedRuleGroups.BotControl});if(s)o=W.setRateLimit(o,{name:"GlobalRateLimit",priority:l++,requestsPerWindow:a*5});return{webAcl:o,logicalId:c}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}function fa(e){let t=e.split(".")[0]??"";return t==="a1"||/^[a-z]+\d+g[a-z]*$/.test(t)}function ha(e="t3.micro"){return`/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${fa(e)?"arm64":"x86_64"}`}function lr(e="t3.micro"){return`{{resolve:ssm:${ha(e)}}}`}class x{static createServer(e){let{slug:t,environment:n,instanceType:r="t3.micro",imageId:i=lr(r),keyName:s,securityGroupIds:a,subnetId:o,userData:c,volumeSize:l=20,volumeType:u="gp3",encrypted:m=!0}=e,p=S({slug:t,environment:n,resourceType:"ec2"}),g=f(p),y={Type:"AWS::EC2::Instance",Properties:{ImageId:i,InstanceType:r,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:n}]}};if(s)y.Properties.KeyName=s;if(a)y.Properties.SecurityGroupIds=a;if(o)y.Properties.SubnetId=o;if(c)y.Properties.UserData=C.Base64(c);return y.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:l,VolumeType:u,Encrypted:m,DeleteOnTermination:!0}}],{instance:y,logicalId:g}}static createSecurityGroup(e){let{slug:t,environment:n,vpcId:r,description:i,ingress:s=[],egress:a=[]}=e,o=S({slug:t,environment:n,resourceType:"sg"}),c=f(o),l={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:i||`Security group for ${t} ${n}`,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}};if(r)l.Properties.VpcId=r;if(s.length>0)l.Properties.SecurityGroupIngress=s.map((u)=>({IpProtocol:u.protocol,FromPort:u.fromPort,ToPort:u.toPort,CidrIp:u.cidr,SourceSecurityGroupId:u.sourceSecurityGroupId}));if(a.length>0)l.Properties.SecurityGroupEgress=a.map((u)=>({IpProtocol:u.protocol,FromPort:u.fromPort,ToPort:u.toPort,CidrIp:u.cidr,DestinationSecurityGroupId:u.sourceSecurityGroupId}));return{securityGroup:l,logicalId:c}}static createWebServerSecurityGroup(e,t,n){return x.createSecurityGroup({slug:e,environment:t,vpcId:n,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(e){let{slug:t,environment:n,scheme:r="internet-facing",subnets:i,securityGroups:s,type:a="application"}=e,o=S({slug:t,environment:n,resourceType:"alb"}),c=f(o),l={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:o,Scheme:r,Type:a,Subnets:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}};if(s)l.Properties.SecurityGroups=s;return{loadBalancer:l,logicalId:c}}static createTargetGroup(e){let{slug:t,environment:n,port:r,protocol:i="HTTP",vpcId:s,targetType:a="ip",healthCheckPath:o="/",healthCheckInterval:c=30,healthCheckTimeout:l=5,healthyThreshold:u=2,unhealthyThreshold:m=3}=e,p=S({slug:t,environment:n,resourceType:"tg"}),g=f(p);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:p,Port:r,Protocol:i,VpcId:s,TargetType:a,HealthCheckEnabled:!0,HealthCheckProtocol:i,HealthCheckPath:o,HealthCheckIntervalSeconds:c,HealthCheckTimeoutSeconds:l,HealthyThresholdCount:u,UnhealthyThresholdCount:m,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:n}]}},logicalId:g}}static createListener(e,t){let{port:n,protocol:r="HTTP",certificateArn:i,defaultTargetGroupArn:s}=t,a=f(`listener-${e}-${n}`),o={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:C.Ref(e),Port:n,Protocol:r,DefaultActions:[{Type:"forward",TargetGroupArn:s}]}};if(r==="HTTPS"&&i)o.Properties.Certificates=[{CertificateArn:i}],o.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:o,logicalId:a}}static createEcsCluster(e,t){let n=S({slug:e,environment:t,resourceType:"ecs-cluster"}),r=f(n);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:n,Tags:[{Key:"Name",Value:n},{Key:"Environment",Value:t}]}},logicalId:r}}static createFargateService(e){let{slug:t,environment:n,image:r,cpu:i="256",memory:s="512",desiredCount:a=1,containerPort:o=8080,environmentVariables:c={},secrets:l=[],healthCheck:u,logGroup:m,subnets:p,securityGroups:g,targetGroupArn:y}=e,{cluster:h,logicalId:b}=x.createEcsCluster(t,n),v=S({slug:t,environment:n,resourceType:"fargate"}),T=f(`${v}-execution-role`),A={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"]}},R=f(`${v}-task-role`),P={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},E=f(`${v}-task`),w={Type:"AWS::ECS::TaskDefinition",Properties:{Family:v,TaskRoleArn:C.GetAtt(R,"Arn"),ExecutionRoleArn:C.GetAtt(T,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:i,Memory:s,ContainerDefinitions:[{Name:t,Image:r,Essential:!0,PortMappings:[{ContainerPort:o,Protocol:"tcp"}],Environment:Object.entries(c).map(([k,O])=>({Name:k,Value:O})),Secrets:l.map((k)=>({Name:k.name,ValueFrom:k.valueFrom}))}],Tags:[{Key:"Name",Value:v},{Key:"Environment",Value:n}]}};if(u)w.Properties.ContainerDefinitions[0].HealthCheck={Command:u.command,Interval:u.interval||30,Timeout:u.timeout||5,Retries:u.retries||3,StartPeriod:60};if(m)w.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":m,"awslogs-region":C.Ref("AWS::Region"),"awslogs-stream-prefix":t}};let I=f(`${v}-service`),D={Type:"AWS::ECS::Service",Properties:{ServiceName:v,Cluster:C.Ref(b),TaskDefinition:C.Ref(E),DesiredCount:a,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:p,SecurityGroups:g,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:v},{Key:"Environment",Value:n}]}};if(y)D.Properties.LoadBalancers=[{TargetGroupArn:y,ContainerName:t,ContainerPort:o}];return{cluster:h,taskDefinition:w,service:D,taskRole:P,executionRole:A,clusterLogicalId:b,taskDefinitionLogicalId:E,serviceLogicalId:I,taskRoleLogicalId:R,executionRoleLogicalId:T}}static createLambdaFunction(e){let{slug:t,environment:n,runtime:r,handler:i,code:s,timeout:a=30,memorySize:o=128,environmentVariables:c={},vpcConfig:l}=e,u=S({slug:t,environment:n,resourceType:"lambda"}),m=f(u),p=f(`${u}-role`),g={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(l)g.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let y={Type:"AWS::Lambda::Function",Properties:{FunctionName:u,Runtime:r,Role:C.GetAtt(p,"Arn"),Handler:i,Code:{...s.s3Bucket&&{S3Bucket:s.s3Bucket},...s.s3Key&&{S3Key:s.s3Key},...s.zipFile&&{ZipFile:s.zipFile}},Timeout:a,MemorySize:o,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n}]}};if(Object.keys(c).length>0)y.Properties.Environment={Variables:c};if(l)y.Properties.VpcConfig={SecurityGroupIds:l.securityGroupIds,SubnetIds:l.subnetIds};return{lambdaFunction:y,role:g,logicalId:m,roleLogicalId:p}}static generateNodeServerUserData(e={}){let{nodeVersion:t="20",appRepo:n,environment:r={}}=e,i=Object.entries(r).map(([s,a])=>`echo "export ${s}='${a}'" >> /etc/environment`).join(`
212
+ `.trim()};static Config={ttl:(e)=>{let{min:t=0,max:n=86400,default:r=86400}=e;return{MinTTL:t,MaxTTL:n,DefaultTTL:r}},cookies:(e,t)=>{let n={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&t)n.WhitelistedNames=t;return n},allowedMethods:(e)=>{let t={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return t[e]||t.GET_HEAD},cachedMethods:(e)=>{let t={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return t[e]||t.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:(e)=>{let{ttl:t={min:0,max:86400,default:86400},cookies:n="none",allowedCookies:r,allowedMethods:i="GET_HEAD",cachedMethods:s="GET_HEAD",compress:a=!0,forwardQueryString:o=!0,forwardHeaders:c=[]}=e;return{MinTTL:t.min,MaxTTL:t.max,DefaultTTL:t.default,Compress:a,AllowedMethods:se.Config.allowedMethods(i),CachedMethods:se.Config.cachedMethods(s),ForwardedValues:{QueryString:o,Headers:c,Cookies:se.Config.cookies(n,r)}}}};static applyConfig(e,t){let n=e.Properties.DistributionConfig.DefaultCacheBehavior;if(t.ttl)n.MinTTL=t.ttl.min,n.MaxTTL=t.ttl.max,n.DefaultTTL=t.ttl.default;if(t.compress!==void 0)n.Compress=t.compress;if(t.allowedMethods)n.AllowedMethods=se.Config.allowedMethods(t.allowedMethods);if(t.cachedMethods)n.CachedMethods=se.Config.cachedMethods(t.cachedMethods);if(t.cookies){if(!n.ForwardedValues)n.ForwardedValues={QueryString:!0};n.ForwardedValues.Cookies=se.Config.cookies(t.cookies,t.allowedCookies)}return e}}var da=[403,404,500,502,503,504],ma="TsCloud::StorageFailover",pa="AllowCloudFrontFailoverRead",ga=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,ya=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function cd(e){let{failover:t,primaryBucket:n,primaryRegion:r}=e,i=e.where??"storage failover";if(!t||typeof t!=="object")throw Error(`${i}.failover must be an object such as { region: 'us-west-2' }.`);if(!t.region||!ga.test(t.region))throw Error(`${i}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(t.region)}.`);if(t.region===r)throw Error(`${i}.failover.region is ${t.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let s=t.bucket??`${n}-${t.region}`;if(!ya.test(s)||s.includes("..")){let a=t.bucket===void 0&&s.length>63?` The default name (<primary bucket>-<region>) is ${s.length} characters; S3 allows 63. Set ${i}.failover.bucket.`:"";throw Error(`${i}.failover: "${s}" is not a valid S3 bucket name.${a}`)}if(s===n)throw Error(`${i}.failover.bucket must differ from the primary bucket "${n}".`);return{replicaBucket:s,replicaRegion:t.region,replicate:t.replicate!==!1,statusCodes:ht(t.statusCodes??da),primaryConnection:Ge(t,`${i}.failover`)}}function ld(e,t){return`${e}.s3.${t}.amazonaws.com`}function ud(e){let t=`arn:aws:s3:::${e.primaryBucket}`,n=`arn:aws:s3:::${e.replicaBucket}`;return{Type:"AWS::IAM::Role",Properties:{...e.roleName?{RoleName:e.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:t},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${t}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${n}/*`}]}}]}}}function dd(e){return{Role:e.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${e.replicaBucket}`}}]}}function md(e){return{Sid:pa,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function pd(e){let n=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[ma];return Array.isArray(n)?n:[]}class J{static createHostedZone(e){let{domain:t,slug:n,environment:r,comment:i}=e,s=S({slug:n,environment:r,resourceType:"hostedzone"}),a=f(`${s}-${t.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:t,HostedZoneConfig:{Comment:i||`Hosted zone for ${t}`}}},logicalId:a}}static createRecord(e){let{hostedZoneId:t,hostedZoneName:n,name:r,type:i,ttl:s,values:a,aliasTarget:o}=e,c=f(`record-${r.replace(/\./g,"")}-${i}`),l={Type:"AWS::Route53::RecordSet",Properties:{Name:r,Type:i}};if(t)l.Properties.HostedZoneId=t;else if(n)l.Properties.HostedZoneName=n;if(o)l.Properties.AliasTarget={DNSName:o.dnsName,HostedZoneId:o.hostedZoneId,EvaluateTargetHealth:o.evaluateTargetHealth??!1};else l.Properties.TTL=s||300,l.Properties.ResourceRecords=a||[];return{record:l,logicalId:c}}static createCloudFrontAlias(e,t,n){return J.createRecord({hostedZoneId:n,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,t,n,r){return J.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:n,evaluateTargetHealth:!0}})}static createCname(e,t,n,r=300){return J.createRecord({hostedZoneId:n,name:e,type:"CNAME",ttl:r,values:[t]})}static createWwwRedirect(e,t){return J.createRecord({hostedZoneId:t,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,t,n,r=300){return J.createRecord({hostedZoneId:n,name:e,type:"MX",ttl:r,values:t.map((i)=>`${i.priority} ${i.server}`)})}static createTxtRecord(e,t,n,r=300){return J.createRecord({hostedZoneId:n,name:e,type:"TXT",ttl:r,values:[`"${t}"`]})}static createSpfRecord(e,t,n){return J.createTxtRecord(e,t,n)}static createDmarcRecord(e,t,n,r){let i=`v=DMARC1; p=${t}; rua=mailto:${n}`;return J.createTxtRecord(`_dmarc.${e}`,i,r)}static createS3WebsiteAlias(e,t,n,r){return J.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:n,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(e,t){return`${e}.s3-website-${t}.amazonaws.com`}static createStoreRecord(e,t,n){return J.createCname(`store.${e}`,t,n)}static createApiRecord(e,t,n){return J.createCname(`api.${e}`,t,n)}static createDocsRecord(e,t,n){return J.createCname(`docs.${e}`,t,n)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class U{static createCertificate(e){let{domain:t,subdomains:n=[],slug:r,environment:i,validationMethod:s="DNS",hostedZoneId:a}=e,o=S({slug:r,environment:i,resourceType:"acm"}),c=f(`${o}-${t.replace(/\./g,"")}`),l=[t];for(let m of n)if(m==="*")l.push(`*.${t}`);else l.push(`${m}.${t}`);let u={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:t,SubjectAlternativeNames:l,ValidationMethod:s}};if(s==="DNS"&&a)u.Properties.DomainValidationOptions=l.map((m)=>({DomainName:m,HostedZoneId:a}));return{certificate:u,logicalId:c}}static createKmsKey(e){let{description:t,slug:n,environment:r,enableRotation:i=!0,multiRegion:s=!1}=e,a=S({slug:n,environment:r,resourceType:"kms"}),o=f(a),c={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:v.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:"*"}]},l={Type:"AWS::KMS::Key",Properties:{Description:t,Enabled:!0,EnableKeyRotation:i,KeyPolicy:c,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:s}},u=f(`${a}-alias`),m={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${n}-${r}`,TargetKeyId:v.Ref(o)}};return{key:l,alias:m,logicalId:o,aliasId:u}}static createFirewall(e){let{slug:t,environment:n,scope:r="CLOUDFRONT",defaultAction:i="allow"}=e,s=S({slug:t,environment:n,resourceType:"waf"}),a=f(s);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:s,Scope:r,DefaultAction:i==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${t} ${n}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-metric`}}},logicalId:a}}static setRateLimit(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{RateBasedStatement:{Limit:t.requestsPerWindow,AggregateKeyType:t.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static blockCountries(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{GeoMatchStatement:{CountryCodes:t.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static blockIpAddresses(e,t,n,r){let i=S({slug:n,environment:r,resourceType:"ipset"}),s=f(`${i}-${t.name}`),a={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${i}-${t.name}`,Scope:e.Properties.Scope,IPAddressVersion:t.ipVersion||"IPV4",Addresses:t.ipAddresses,Description:`Blocked IPs for ${t.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{IPSetReferenceStatement:{Arn:v.GetAtt(s,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),{webAcl:e,ipSet:a,ipSetLogicalId:s}}static addManagedRules(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];let n={ManagedRuleGroupStatement:{VendorName:t.vendorName,Name:t.ruleName}};if(t.excludedRules&&t.excludedRules.length>0)n.ManagedRuleGroupStatement.ExcludedRules=t.excludedRules.map((r)=>({Name:r}));return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:n,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}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(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];let n=t.paths.map((r)=>({SearchString:r,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{RateBasedStatement:{Limit:t.requestsPerWindow,AggregateKeyType:t.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:n.map((r)=>({ByteMatchStatement:r}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static setHeaderRateLimit(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];let n={RateBasedStatement:{Limit:t.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:t.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(t.headerValue)n.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:t.headerValue,FieldToMatch:{SingleHeader:{Name:t.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:n,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static protectLoginEndpoint(e,t){let{loginPaths:n,priority:r,requestsPerMinute:i=10}=t;return U.setPathRateLimit(e,{name:"LoginRateLimit",priority:r,requestsPerWindow:i*5,paths:n}),e}static protectApiEndpoints(e,t){let{apiPaths:n,priority:r,requestsPerMinute:i=100}=t;return U.setPathRateLimit(e,{name:"ApiRateLimit",priority:r,requestsPerWindow:i*5,paths:n}),e}static createProtectedFirewall(e){let{slug:t,environment:n,scope:r="CLOUDFRONT",enableBotControl:i=!1,enableRateLimiting:s=!0,rateLimitPerMinute:a=2000}=e,{webAcl:o,logicalId:c}=U.createFirewall({slug:t,environment:n,scope:r,defaultAction:"allow"}),l=0;if(o=U.addManagedRules(o,{name:"AWSIPReputationList",priority:l++,...U.ManagedRuleGroups.AmazonIpReputation}),o=U.addManagedRules(o,{name:"AWSAnonymousIPList",priority:l++,...U.ManagedRuleGroups.AnonymousIpList}),o=U.addManagedRules(o,{name:"AWSCoreRuleSet",priority:l++,...U.ManagedRuleGroups.CoreRuleSet}),o=U.addManagedRules(o,{name:"AWSKnownBadInputs",priority:l++,...U.ManagedRuleGroups.KnownBadInputs}),o=U.addManagedRules(o,{name:"AWSSQLi",priority:l++,...U.ManagedRuleGroups.SqlDatabase}),i)o=U.addManagedRules(o,{name:"AWSBotControl",priority:l++,...U.ManagedRuleGroups.BotControl});if(s)o=U.setRateLimit(o,{name:"GlobalRateLimit",priority:l++,requestsPerWindow:a*5});return{webAcl:o,logicalId:c}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}function fa(e){let t=e.split(".")[0]??"";return t==="a1"||/^[a-z]+\d+g[a-z]*$/.test(t)}function ha(e="t3.micro"){return`/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${fa(e)?"arm64":"x86_64"}`}function lr(e="t3.micro"){return`{{resolve:ssm:${ha(e)}}}`}class x{static createServer(e){let{slug:t,environment:n,instanceType:r="t3.micro",imageId:i=lr(r),keyName:s,securityGroupIds:a,subnetId:o,userData:c,volumeSize:l=20,volumeType:u="gp3",encrypted:m=!0}=e,p=S({slug:t,environment:n,resourceType:"ec2"}),g=f(p),y={Type:"AWS::EC2::Instance",Properties:{ImageId:i,InstanceType:r,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:n}]}};if(s)y.Properties.KeyName=s;if(a)y.Properties.SecurityGroupIds=a;if(o)y.Properties.SubnetId=o;if(c)y.Properties.UserData=v.Base64(c);return y.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:l,VolumeType:u,Encrypted:m,DeleteOnTermination:!0}}],{instance:y,logicalId:g}}static createSecurityGroup(e){let{slug:t,environment:n,vpcId:r,description:i,ingress:s=[],egress:a=[]}=e,o=S({slug:t,environment:n,resourceType:"sg"}),c=f(o),l={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:i||`Security group for ${t} ${n}`,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}};if(r)l.Properties.VpcId=r;if(s.length>0)l.Properties.SecurityGroupIngress=s.map((u)=>({IpProtocol:u.protocol,FromPort:u.fromPort,ToPort:u.toPort,CidrIp:u.cidr,SourceSecurityGroupId:u.sourceSecurityGroupId}));if(a.length>0)l.Properties.SecurityGroupEgress=a.map((u)=>({IpProtocol:u.protocol,FromPort:u.fromPort,ToPort:u.toPort,CidrIp:u.cidr,DestinationSecurityGroupId:u.sourceSecurityGroupId}));return{securityGroup:l,logicalId:c}}static createWebServerSecurityGroup(e,t,n){return x.createSecurityGroup({slug:e,environment:t,vpcId:n,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(e){let{slug:t,environment:n,scheme:r="internet-facing",subnets:i,securityGroups:s,type:a="application"}=e,o=S({slug:t,environment:n,resourceType:"alb"}),c=f(o),l={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:o,Scheme:r,Type:a,Subnets:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}};if(s)l.Properties.SecurityGroups=s;return{loadBalancer:l,logicalId:c}}static createTargetGroup(e){let{slug:t,environment:n,port:r,protocol:i="HTTP",vpcId:s,targetType:a="ip",healthCheckPath:o="/",healthCheckInterval:c=30,healthCheckTimeout:l=5,healthyThreshold:u=2,unhealthyThreshold:m=3}=e,p=S({slug:t,environment:n,resourceType:"tg"}),g=f(p);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:p,Port:r,Protocol:i,VpcId:s,TargetType:a,HealthCheckEnabled:!0,HealthCheckProtocol:i,HealthCheckPath:o,HealthCheckIntervalSeconds:c,HealthCheckTimeoutSeconds:l,HealthyThresholdCount:u,UnhealthyThresholdCount:m,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:n}]}},logicalId:g}}static createListener(e,t){let{port:n,protocol:r="HTTP",certificateArn:i,defaultTargetGroupArn:s}=t,a=f(`listener-${e}-${n}`),o={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:v.Ref(e),Port:n,Protocol:r,DefaultActions:[{Type:"forward",TargetGroupArn:s}]}};if(r==="HTTPS"&&i)o.Properties.Certificates=[{CertificateArn:i}],o.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:o,logicalId:a}}static createEcsCluster(e,t){let n=S({slug:e,environment:t,resourceType:"ecs-cluster"}),r=f(n);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:n,Tags:[{Key:"Name",Value:n},{Key:"Environment",Value:t}]}},logicalId:r}}static createFargateService(e){let{slug:t,environment:n,image:r,cpu:i="256",memory:s="512",desiredCount:a=1,containerPort:o=8080,environmentVariables:c={},secrets:l=[],healthCheck:u,logGroup:m,subnets:p,securityGroups:g,targetGroupArn:y}=e,{cluster:h,logicalId:b}=x.createEcsCluster(t,n),C=S({slug:t,environment:n,resourceType:"fargate"}),T=f(`${C}-execution-role`),A={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"]}},R=f(`${C}-task-role`),P={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},E=f(`${C}-task`),w={Type:"AWS::ECS::TaskDefinition",Properties:{Family:C,TaskRoleArn:v.GetAtt(R,"Arn"),ExecutionRoleArn:v.GetAtt(T,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:i,Memory:s,ContainerDefinitions:[{Name:t,Image:r,Essential:!0,PortMappings:[{ContainerPort:o,Protocol:"tcp"}],Environment:Object.entries(c).map(([k,O])=>({Name:k,Value:O})),Secrets:l.map((k)=>({Name:k.name,ValueFrom:k.valueFrom}))}],Tags:[{Key:"Name",Value:C},{Key:"Environment",Value:n}]}};if(u)w.Properties.ContainerDefinitions[0].HealthCheck={Command:u.command,Interval:u.interval||30,Timeout:u.timeout||5,Retries:u.retries||3,StartPeriod:60};if(m)w.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":m,"awslogs-region":v.Ref("AWS::Region"),"awslogs-stream-prefix":t}};let I=f(`${C}-service`),D={Type:"AWS::ECS::Service",Properties:{ServiceName:C,Cluster:v.Ref(b),TaskDefinition:v.Ref(E),DesiredCount:a,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:p,SecurityGroups:g,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:C},{Key:"Environment",Value:n}]}};if(y)D.Properties.LoadBalancers=[{TargetGroupArn:y,ContainerName:t,ContainerPort:o}];return{cluster:h,taskDefinition:w,service:D,taskRole:P,executionRole:A,clusterLogicalId:b,taskDefinitionLogicalId:E,serviceLogicalId:I,taskRoleLogicalId:R,executionRoleLogicalId:T}}static createLambdaFunction(e){let{slug:t,environment:n,runtime:r,handler:i,code:s,timeout:a=30,memorySize:o=128,environmentVariables:c={},vpcConfig:l}=e,u=S({slug:t,environment:n,resourceType:"lambda"}),m=f(u),p=f(`${u}-role`),g={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(l)g.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let y={Type:"AWS::Lambda::Function",Properties:{FunctionName:u,Runtime:r,Role:v.GetAtt(p,"Arn"),Handler:i,Code:{...s.s3Bucket&&{S3Bucket:s.s3Bucket},...s.s3Key&&{S3Key:s.s3Key},...s.zipFile&&{ZipFile:s.zipFile}},Timeout:a,MemorySize:o,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n}]}};if(Object.keys(c).length>0)y.Properties.Environment={Variables:c};if(l)y.Properties.VpcConfig={SecurityGroupIds:l.securityGroupIds,SubnetIds:l.subnetIds};return{lambdaFunction:y,role:g,logicalId:m,roleLogicalId:p}}static generateNodeServerUserData(e={}){let{nodeVersion:t="20",appRepo:n,environment:r={}}=e,i=Object.entries(r).map(([s,a])=>`echo "export ${s}='${a}'" >> /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(e){let{slug:t,environment:n,imageId:r,instanceType:i,keyName:s,securityGroups:a,userData:o,volumeSize:c=20,volumeType:l="gp3",encrypted:u=!0,iamInstanceProfile:m}=e,p=S({slug:t,environment:n,resourceType:"launch-config"}),g=f(p),y={Type:"AWS::AutoScaling::LaunchConfiguration",Properties:{ImageId:r,InstanceType:i,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:c,VolumeType:l,Encrypted:u,DeleteOnTermination:!0}}]}};if(s)y.Properties.KeyName=s;if(a)y.Properties.SecurityGroups=a;if(o)y.Properties.UserData=C.Base64(o);if(m)y.Properties.IamInstanceProfile=m;return{launchConfiguration:y,logicalId:g}}static createAutoScalingGroup(e){let{slug:t,environment:n,launchConfigurationName:r,minSize:i,maxSize:s,desiredCapacity:a,vpcZoneIdentifier:o,targetGroupArns:c,healthCheckType:l="EC2",healthCheckGracePeriod:u=300,cooldown:m=300,tags:p={}}=e,g=S({slug:t,environment:n,resourceType:"asg"}),y=f(g),h={Type:"AWS::AutoScaling::AutoScalingGroup",Properties:{AutoScalingGroupName:g,LaunchConfigurationName:r,MinSize:i,MaxSize:s,HealthCheckType:l,HealthCheckGracePeriod:u,Cooldown:m,Tags:[{Key:"Name",Value:g,PropagateAtLaunch:!0},{Key:"Environment",Value:n,PropagateAtLaunch:!0},...Object.entries(p).map(([b,v])=>({Key:b,Value:v,PropagateAtLaunch:!0}))]}};if(a!==void 0)h.Properties.DesiredCapacity=a;if(o)h.Properties.VPCZoneIdentifier=o;if(c)h.Properties.TargetGroupARNs=c;return h.UpdatePolicy={AutoScalingRollingUpdate:{MaxBatchSize:1,MinInstancesInService:Math.max(0,i-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:h,logicalId:y}}static createScalingPolicy(e){let{slug:t,environment:n,autoScalingGroupName:r,policyType:i="TargetTrackingScaling",targetValue:s=70,predefinedMetricType:a="ASGAverageCPUUtilization"}=e,o=S({slug:t,environment:n,resourceType:"scaling-policy"}),c=f(o),l={Type:"AWS::AutoScaling::ScalingPolicy",Properties:{AutoScalingGroupName:r,PolicyType:i}};if(i==="TargetTrackingScaling")l.Properties.TargetTrackingConfiguration={PredefinedMetricSpecification:{PredefinedMetricType:a},TargetValue:s};return{scalingPolicy:l,logicalId:c}}static AutoScaling={smallWebServer:(e,t,n,r,i)=>x.createAutoScalingGroup({slug:e,environment:t,launchConfigurationName:n,minSize:2,maxSize:4,desiredCapacity:2,vpcZoneIdentifier:r,targetGroupArns:i,healthCheckType:i?"ELB":"EC2",healthCheckGracePeriod:300}),mediumWebServer:(e,t,n,r,i)=>x.createAutoScalingGroup({slug:e,environment:t,launchConfigurationName:n,minSize:3,maxSize:10,desiredCapacity:3,vpcZoneIdentifier:r,targetGroupArns:i,healthCheckType:i?"ELB":"EC2",healthCheckGracePeriod:300}),largeWebServer:(e,t,n,r,i)=>x.createAutoScalingGroup({slug:e,environment:t,launchConfigurationName:n,minSize:5,maxSize:20,desiredCapacity:5,vpcZoneIdentifier:r,targetGroupArns:i,healthCheckType:i?"ELB":"EC2",healthCheckGracePeriod:300}),cpuScaling:(e,t,n,r=70)=>x.createScalingPolicy({slug:e,environment:t,autoScalingGroupName:n,policyType:"TargetTrackingScaling",predefinedMetricType:"ASGAverageCPUUtilization",targetValue:r}),requestCountScaling:(e,t,n,r=1000)=>x.createScalingPolicy({slug:e,environment:t,autoScalingGroupName:n,policyType:"TargetTrackingScaling",predefinedMetricType:"ALBRequestCountPerTarget",targetValue:r})};static Secrets={fromSecretsManager:(e)=>Object.entries(e).map(([t,n])=>({name:t,valueFrom:n})),fromJsonSecret:(e,t)=>`${e}:${t}::`,fromSecretVersion:(e,t)=>`${e}::${t}:`,fromSecretVersionStage:(e,t)=>`${e}:::${t}`,createAccessPolicy:(e)=>({PolicyName:"SecretsManagerAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],Resource:e}]}}),createKmsPolicy:(e)=>({PolicyName:"KMSDecryptAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["kms:Decrypt"],Resource:e}]}}),buildSecretArn:(e)=>`arn:aws:secretsmanager:${e.region}:${e.accountId}:secret:${e.secretName}`,buildSecretArnPattern:(e)=>{let t=e.region||"*",n=e.accountId||"*";return`arn:aws:secretsmanager:${t}:${n}:secret:${e.secretNamePrefix}*`},commonAppSecrets:(e)=>({DATABASE_URL:`${e}/database-url`,DATABASE_PASSWORD:`${e}/database-password`,REDIS_URL:`${e}/redis-url`,REDIS_PASSWORD:`${e}/redis-password`,API_KEY:`${e}/api-key`,JWT_SECRET:`${e}/jwt-secret`,ENCRYPTION_KEY:`${e}/encryption-key`,AWS_ACCESS_KEY_ID:`${e}/aws-access-key-id`,AWS_SECRET_ACCESS_KEY:`${e}/aws-secret-access-key`,MAIL_PASSWORD:`${e}/mail-password`,STRIPE_SECRET_KEY:`${e}/stripe-secret-key`,STRIPE_WEBHOOK_SECRET:`${e}/stripe-webhook-secret`})};static createFargateServiceWithSecrets(e){let{secretArns:t=[],kmsKeyArns:n=[],...r}=e,i=x.createFargateService(r);if(t.length>0){if(!i.executionRole.Properties.Policies)i.executionRole.Properties.Policies=[];if(i.executionRole.Properties.Policies.push(x.Secrets.createAccessPolicy(t)),n.length>0)i.executionRole.Properties.Policies.push(x.Secrets.createKmsPolicy(n))}return i}static generateSecretReferences(e){return e.secrets.map((t)=>{let n=`arn:aws:secretsmanager:${e.region}:${e.accountId}:secret:${e.secretPrefix}/${t}`;return{name:t.toUpperCase().replace(/-/g,"_"),valueFrom:n}})}static EnvSecrets={database:(e)=>[{name:"DB_HOST",valueFrom:`${e}:host::`},{name:"DB_PORT",valueFrom:`${e}:port::`},{name:"DB_USERNAME",valueFrom:`${e}:username::`},{name:"DB_PASSWORD",valueFrom:`${e}:password::`},{name:"DB_NAME",valueFrom:`${e}:dbname::`}],redis:(e)=>[{name:"REDIS_HOST",valueFrom:`${e}:host::`},{name:"REDIS_PORT",valueFrom:`${e}:port::`},{name:"REDIS_PASSWORD",valueFrom:`${e}:password::`}],apiCredentials:(e)=>[{name:"API_KEY",valueFrom:`${e}:apiKey::`},{name:"API_SECRET",valueFrom:`${e}:apiSecret::`}],mail:(e)=>[{name:"MAIL_HOST",valueFrom:`${e}:host::`},{name:"MAIL_PORT",valueFrom:`${e}:port::`},{name:"MAIL_USERNAME",valueFrom:`${e}:username::`},{name:"MAIL_PASSWORD",valueFrom:`${e}:password::`}],awsCredentials:(e)=>[{name:"AWS_ACCESS_KEY_ID",valueFrom:`${e}:accessKeyId::`},{name:"AWS_SECRET_ACCESS_KEY",valueFrom:`${e}:secretAccessKey::`}]};static createJumpBox(e){let{slug:t,environment:n,vpcId:r,subnetId:i,keyName:s,instanceType:a="t3.micro",imageId:o=lr(a),mountEfs:c,databaseTools:l=!1}=e,u=e.allowedCidrs??(s?["0.0.0.0/0"]:[]),m=S({slug:t,environment:n,resourceType:"jumpbox"}),p=f(`${m}-sg`),g={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:`${m}-sg`,GroupDescription:`Security group for ${m} JumpBox access`,VpcId:r,SecurityGroupIngress:u.map((E)=>({IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:E,Description:`SSH access from ${E}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound traffic"}],Tags:[{Key:"Name",Value:`${m}-sg`},{Key:"Environment",Value:n}]}},y=f(`${m}-role`),h={Type:"AWS::IAM::Role",Properties:{RoleName:`${m}-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:c?[{PolicyName:"EFSAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess"],Resource:"*"}]}}]:void 0}},b=f(`${m}-profile`),v={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:`${m}-profile`,Roles:[C.Ref(y)]}},T=`#!/bin/bash
313
+ `}static createLaunchConfiguration(e){let{slug:t,environment:n,imageId:r,instanceType:i,keyName:s,securityGroups:a,userData:o,volumeSize:c=20,volumeType:l="gp3",encrypted:u=!0,iamInstanceProfile:m}=e,p=S({slug:t,environment:n,resourceType:"launch-config"}),g=f(p),y={Type:"AWS::AutoScaling::LaunchConfiguration",Properties:{ImageId:r,InstanceType:i,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:c,VolumeType:l,Encrypted:u,DeleteOnTermination:!0}}]}};if(s)y.Properties.KeyName=s;if(a)y.Properties.SecurityGroups=a;if(o)y.Properties.UserData=v.Base64(o);if(m)y.Properties.IamInstanceProfile=m;return{launchConfiguration:y,logicalId:g}}static createAutoScalingGroup(e){let{slug:t,environment:n,launchConfigurationName:r,minSize:i,maxSize:s,desiredCapacity:a,vpcZoneIdentifier:o,targetGroupArns:c,healthCheckType:l="EC2",healthCheckGracePeriod:u=300,cooldown:m=300,tags:p={}}=e,g=S({slug:t,environment:n,resourceType:"asg"}),y=f(g),h={Type:"AWS::AutoScaling::AutoScalingGroup",Properties:{AutoScalingGroupName:g,LaunchConfigurationName:r,MinSize:i,MaxSize:s,HealthCheckType:l,HealthCheckGracePeriod:u,Cooldown:m,Tags:[{Key:"Name",Value:g,PropagateAtLaunch:!0},{Key:"Environment",Value:n,PropagateAtLaunch:!0},...Object.entries(p).map(([b,C])=>({Key:b,Value:C,PropagateAtLaunch:!0}))]}};if(a!==void 0)h.Properties.DesiredCapacity=a;if(o)h.Properties.VPCZoneIdentifier=o;if(c)h.Properties.TargetGroupARNs=c;return h.UpdatePolicy={AutoScalingRollingUpdate:{MaxBatchSize:1,MinInstancesInService:Math.max(0,i-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:h,logicalId:y}}static createScalingPolicy(e){let{slug:t,environment:n,autoScalingGroupName:r,policyType:i="TargetTrackingScaling",targetValue:s=70,predefinedMetricType:a="ASGAverageCPUUtilization"}=e,o=S({slug:t,environment:n,resourceType:"scaling-policy"}),c=f(o),l={Type:"AWS::AutoScaling::ScalingPolicy",Properties:{AutoScalingGroupName:r,PolicyType:i}};if(i==="TargetTrackingScaling")l.Properties.TargetTrackingConfiguration={PredefinedMetricSpecification:{PredefinedMetricType:a},TargetValue:s};return{scalingPolicy:l,logicalId:c}}static AutoScaling={smallWebServer:(e,t,n,r,i)=>x.createAutoScalingGroup({slug:e,environment:t,launchConfigurationName:n,minSize:2,maxSize:4,desiredCapacity:2,vpcZoneIdentifier:r,targetGroupArns:i,healthCheckType:i?"ELB":"EC2",healthCheckGracePeriod:300}),mediumWebServer:(e,t,n,r,i)=>x.createAutoScalingGroup({slug:e,environment:t,launchConfigurationName:n,minSize:3,maxSize:10,desiredCapacity:3,vpcZoneIdentifier:r,targetGroupArns:i,healthCheckType:i?"ELB":"EC2",healthCheckGracePeriod:300}),largeWebServer:(e,t,n,r,i)=>x.createAutoScalingGroup({slug:e,environment:t,launchConfigurationName:n,minSize:5,maxSize:20,desiredCapacity:5,vpcZoneIdentifier:r,targetGroupArns:i,healthCheckType:i?"ELB":"EC2",healthCheckGracePeriod:300}),cpuScaling:(e,t,n,r=70)=>x.createScalingPolicy({slug:e,environment:t,autoScalingGroupName:n,policyType:"TargetTrackingScaling",predefinedMetricType:"ASGAverageCPUUtilization",targetValue:r}),requestCountScaling:(e,t,n,r=1000)=>x.createScalingPolicy({slug:e,environment:t,autoScalingGroupName:n,policyType:"TargetTrackingScaling",predefinedMetricType:"ALBRequestCountPerTarget",targetValue:r})};static Secrets={fromSecretsManager:(e)=>Object.entries(e).map(([t,n])=>({name:t,valueFrom:n})),fromJsonSecret:(e,t)=>`${e}:${t}::`,fromSecretVersion:(e,t)=>`${e}::${t}:`,fromSecretVersionStage:(e,t)=>`${e}:::${t}`,createAccessPolicy:(e)=>({PolicyName:"SecretsManagerAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],Resource:e}]}}),createKmsPolicy:(e)=>({PolicyName:"KMSDecryptAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["kms:Decrypt"],Resource:e}]}}),buildSecretArn:(e)=>`arn:aws:secretsmanager:${e.region}:${e.accountId}:secret:${e.secretName}`,buildSecretArnPattern:(e)=>{let t=e.region||"*",n=e.accountId||"*";return`arn:aws:secretsmanager:${t}:${n}:secret:${e.secretNamePrefix}*`},commonAppSecrets:(e)=>({DATABASE_URL:`${e}/database-url`,DATABASE_PASSWORD:`${e}/database-password`,REDIS_URL:`${e}/redis-url`,REDIS_PASSWORD:`${e}/redis-password`,API_KEY:`${e}/api-key`,JWT_SECRET:`${e}/jwt-secret`,ENCRYPTION_KEY:`${e}/encryption-key`,AWS_ACCESS_KEY_ID:`${e}/aws-access-key-id`,AWS_SECRET_ACCESS_KEY:`${e}/aws-secret-access-key`,MAIL_PASSWORD:`${e}/mail-password`,STRIPE_SECRET_KEY:`${e}/stripe-secret-key`,STRIPE_WEBHOOK_SECRET:`${e}/stripe-webhook-secret`})};static createFargateServiceWithSecrets(e){let{secretArns:t=[],kmsKeyArns:n=[],...r}=e,i=x.createFargateService(r);if(t.length>0){if(!i.executionRole.Properties.Policies)i.executionRole.Properties.Policies=[];if(i.executionRole.Properties.Policies.push(x.Secrets.createAccessPolicy(t)),n.length>0)i.executionRole.Properties.Policies.push(x.Secrets.createKmsPolicy(n))}return i}static generateSecretReferences(e){return e.secrets.map((t)=>{let n=`arn:aws:secretsmanager:${e.region}:${e.accountId}:secret:${e.secretPrefix}/${t}`;return{name:t.toUpperCase().replace(/-/g,"_"),valueFrom:n}})}static EnvSecrets={database:(e)=>[{name:"DB_HOST",valueFrom:`${e}:host::`},{name:"DB_PORT",valueFrom:`${e}:port::`},{name:"DB_USERNAME",valueFrom:`${e}:username::`},{name:"DB_PASSWORD",valueFrom:`${e}:password::`},{name:"DB_NAME",valueFrom:`${e}:dbname::`}],redis:(e)=>[{name:"REDIS_HOST",valueFrom:`${e}:host::`},{name:"REDIS_PORT",valueFrom:`${e}:port::`},{name:"REDIS_PASSWORD",valueFrom:`${e}:password::`}],apiCredentials:(e)=>[{name:"API_KEY",valueFrom:`${e}:apiKey::`},{name:"API_SECRET",valueFrom:`${e}:apiSecret::`}],mail:(e)=>[{name:"MAIL_HOST",valueFrom:`${e}:host::`},{name:"MAIL_PORT",valueFrom:`${e}:port::`},{name:"MAIL_USERNAME",valueFrom:`${e}:username::`},{name:"MAIL_PASSWORD",valueFrom:`${e}:password::`}],awsCredentials:(e)=>[{name:"AWS_ACCESS_KEY_ID",valueFrom:`${e}:accessKeyId::`},{name:"AWS_SECRET_ACCESS_KEY",valueFrom:`${e}:secretAccessKey::`}]};static createJumpBox(e){let{slug:t,environment:n,vpcId:r,subnetId:i,keyName:s,instanceType:a="t3.micro",imageId:o=lr(a),mountEfs:c,databaseTools:l=!1}=e,u=e.allowedCidrs??(s?["0.0.0.0/0"]:[]),m=S({slug:t,environment:n,resourceType:"jumpbox"}),p=f(`${m}-sg`),g={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:`${m}-sg`,GroupDescription:`Security group for ${m} JumpBox access`,VpcId:r,SecurityGroupIngress:u.map((E)=>({IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:E,Description:`SSH access from ${E}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound traffic"}],Tags:[{Key:"Name",Value:`${m}-sg`},{Key:"Environment",Value:n}]}},y=f(`${m}-role`),h={Type:"AWS::IAM::Role",Properties:{RoleName:`${m}-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:c?[{PolicyName:"EFSAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess"],Resource:"*"}]}}]:void 0}},b=f(`${m}-profile`),C={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:`${m}-profile`,Roles:[v.Ref(y)]}},T=`#!/bin/bash
314
314
  dnf install -y amazon-efs-utils nfs-utils jq wget htop
315
315
  `;if(l)T+=`
316
316
  # Database clients: psql, mysql (MariaDB), redis-cli
@@ -323,7 +323,7 @@ for attempt in $(seq 1 30); do
323
323
  sleep 10
324
324
  done
325
325
  echo "\${FileSystemId}:/ ${E} efs _netdev,tls,nofail 0 0" >> /etc/fstab
326
- `}let A=f(m),R={Type:"AWS::EC2::Instance",DependsOn:[b],Properties:{ImageId:o,InstanceType:a,SubnetId:i,SecurityGroupIds:[C.Ref(p)],IamInstanceProfile:C.Ref(b),UserData:c?{"Fn::Base64":C.Sub(T,{FileSystemId:c.fileSystemId})}:C.Base64(T),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:n},{Key:"Purpose",Value:"JumpBox/Bastion"}]}};if(s)R.Properties.KeyName=s;let P={[p]:g,[y]:h,[b]:v,[A]:R};return{instance:R,securityGroup:g,instanceProfile:v,instanceRole:h,instanceLogicalId:A,securityGroupLogicalId:p,instanceProfileLogicalId:b,instanceRoleLogicalId:y,resources:P}}static JumpBox={withEfsMount:(e)=>x.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,instanceType:e.instanceType,allowedCidrs:e.allowedCidrs,mountEfs:{fileSystemId:e.fileSystemId,mountPath:e.mountPath||"/mnt/efs"}}),minimal:(e)=>x.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,instanceType:"t3.nano",allowedCidrs:e.allowedCidrs}),withDatabaseTools:(e)=>x.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,instanceType:e.instanceType,allowedCidrs:e.allowedCidrs,databaseTools:!0}),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:(e,t="t3")=>`${t}.${e}`,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:(e)=>{let t={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 t[e]||t.medium},toLambdaMemory:(e)=>({nano:128,micro:256,small:512,medium:1024,large:2048,xlarge:4096,"2xlarge":8192})[e]||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:(e)=>{let{size:t,type:n="ssd",encrypted:r=!0,iops:i,throughput:s,deleteOnTermination:a=!0}=e,c={standard:"gp2",ssd:"gp3",premium:"io2",gp2:"gp2",gp3:"gp3",io1:"io1",io2:"io2"}[n]||"gp3",l={VolumeSize:t,VolumeType:c,Encrypted:r,DeleteOnTermination:a};if((c==="io1"||c==="io2"||c==="gp3")&&i)l.Iops=i;if(c==="gp3"&&s)l.Throughput=s;return l},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:(e)=>{let{maxPrice:t,spotInstanceType:n="one-time",interruptionBehavior:r="terminate",blockDurationMinutes:i}=e,s={SpotInstanceType:n,InstanceInterruptionBehavior:r};if(t)s.MaxPrice=t;if(i)s.BlockDurationMinutes=i;return{SpotOptions:s}},presets:{standard:{spotInstanceType:"one-time",interruptionBehavior:"terminate"},persistent:{spotInstanceType:"persistent",interruptionBehavior:"stop"},costOptimized:{maxPrice:"0.05",spotInstanceType:"one-time",interruptionBehavior:"terminate"}}};static MixedInstances={create:(e)=>{let{instanceTypes:t,baseCapacity:n=0,onDemandPercentage:r=20,spotAllocationStrategy:i="capacity-optimized",spotMaxPrice:s}=e,a={OnDemandBaseCapacity:n,OnDemandPercentageAboveBaseCapacity:r,SpotAllocationStrategy:i};if(s)a.SpotMaxPrice=s;let o=t.map(({size:c,weight:l})=>{let u={InstanceType:x.InstanceSize.toInstanceType(c)};if(l)u.WeightedCapacity=String(l);return u});return{MixedInstancesPolicy:{InstancesDistribution:a,LaunchTemplate:{Overrides:o}}}},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:(e)=>{let{min:t,max:n,desired:r=t,scaleUpThreshold:i=70,scaleDownThreshold:s=30,cooldownSeconds:a=300,targetMetric:o="cpu"}=e,c={cpu:"ASGAverageCPUUtilization",memory:"ASGAverageMemoryUtilization",requests:"ALBRequestCountPerTarget"};return{minSize:t,maxSize:n,desiredCapacity:r,scalingPolicies:[{policyType:"TargetTrackingScaling",targetValue:i,predefinedMetricType:c[o]||c.cpu,scaleInCooldown:a,scaleOutCooldown:a}]}},forEcs:(e)=>{let{min:t,max:n,cpuTarget:r=70,memoryTarget:i}=e,s=[{predefinedMetricType:"ECSServiceAverageCPUUtilization",targetValue:r}];if(i)s.push({predefinedMetricType:"ECSServiceAverageMemoryUtilization",targetValue:i});return{minCapacity:t,maxCapacity:n,targetTrackingPolicies:s}},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:(e)=>{let{path:t="/",interval:n=30,timeout:r=5,healthyThreshold:i=2,unhealthyThreshold:s=5,protocol:a="HTTP"}=e,o={HealthCheckIntervalSeconds:n,HealthCheckTimeoutSeconds:r,HealthyThresholdCount:i,UnhealthyThresholdCount:s};if(a!=="TCP")o.HealthCheckPath=t,o.HealthCheckProtocol=a;return o},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:(e)=>{let{certificateArn:t,targetGroupArn:n,port:r=443,sslPolicy:i="ELBSecurityPolicy-TLS13-1-2-2021-06"}=e;return{Port:r,Protocol:"HTTPS",Certificates:[{CertificateArn:t}],SslPolicy:i,DefaultActions:[{Type:"forward",TargetGroupArn:n}]}},httpRedirectListener:(e=80)=>({Port:e,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:(e)=>{let{handler:t,runtime:n="nodejs20.x",timeout:r=30,memorySize:i=256,environmentVariables:s,reservedConcurrency:a}=e,o={Handler:t,Runtime:n,Timeout:r,MemorySize:i};if(s)o.Environment={Variables:s};if(a)o.ReservedConcurrentExecutions=a;return o},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:(e)=>{let{runtime:t="bun",runtimeVersion:n="latest",webServer:r="nginx",processManager:i="systemd",enableSsl:s=!0,sslEmail:a="admin@example.com",domain:o,appPort:c=3000,installDatabaseClients:l=!1,installRedis:u=!1,extraPackages:m=[]}=e,p=`#!/bin/bash
326
+ `}let A=f(m),R={Type:"AWS::EC2::Instance",DependsOn:[b],Properties:{ImageId:o,InstanceType:a,SubnetId:i,SecurityGroupIds:[v.Ref(p)],IamInstanceProfile:v.Ref(b),UserData:c?{"Fn::Base64":v.Sub(T,{FileSystemId:c.fileSystemId})}:v.Base64(T),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:n},{Key:"Purpose",Value:"JumpBox/Bastion"}]}};if(s)R.Properties.KeyName=s;let P={[p]:g,[y]:h,[b]:C,[A]:R};return{instance:R,securityGroup:g,instanceProfile:C,instanceRole:h,instanceLogicalId:A,securityGroupLogicalId:p,instanceProfileLogicalId:b,instanceRoleLogicalId:y,resources:P}}static JumpBox={withEfsMount:(e)=>x.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,instanceType:e.instanceType,allowedCidrs:e.allowedCidrs,mountEfs:{fileSystemId:e.fileSystemId,mountPath:e.mountPath||"/mnt/efs"}}),minimal:(e)=>x.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,instanceType:"t3.nano",allowedCidrs:e.allowedCidrs}),withDatabaseTools:(e)=>x.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,instanceType:e.instanceType,allowedCidrs:e.allowedCidrs,databaseTools:!0}),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:(e,t="t3")=>`${t}.${e}`,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:(e)=>{let t={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 t[e]||t.medium},toLambdaMemory:(e)=>({nano:128,micro:256,small:512,medium:1024,large:2048,xlarge:4096,"2xlarge":8192})[e]||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:(e)=>{let{size:t,type:n="ssd",encrypted:r=!0,iops:i,throughput:s,deleteOnTermination:a=!0}=e,c={standard:"gp2",ssd:"gp3",premium:"io2",gp2:"gp2",gp3:"gp3",io1:"io1",io2:"io2"}[n]||"gp3",l={VolumeSize:t,VolumeType:c,Encrypted:r,DeleteOnTermination:a};if((c==="io1"||c==="io2"||c==="gp3")&&i)l.Iops=i;if(c==="gp3"&&s)l.Throughput=s;return l},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:(e)=>{let{maxPrice:t,spotInstanceType:n="one-time",interruptionBehavior:r="terminate",blockDurationMinutes:i}=e,s={SpotInstanceType:n,InstanceInterruptionBehavior:r};if(t)s.MaxPrice=t;if(i)s.BlockDurationMinutes=i;return{SpotOptions:s}},presets:{standard:{spotInstanceType:"one-time",interruptionBehavior:"terminate"},persistent:{spotInstanceType:"persistent",interruptionBehavior:"stop"},costOptimized:{maxPrice:"0.05",spotInstanceType:"one-time",interruptionBehavior:"terminate"}}};static MixedInstances={create:(e)=>{let{instanceTypes:t,baseCapacity:n=0,onDemandPercentage:r=20,spotAllocationStrategy:i="capacity-optimized",spotMaxPrice:s}=e,a={OnDemandBaseCapacity:n,OnDemandPercentageAboveBaseCapacity:r,SpotAllocationStrategy:i};if(s)a.SpotMaxPrice=s;let o=t.map(({size:c,weight:l})=>{let u={InstanceType:x.InstanceSize.toInstanceType(c)};if(l)u.WeightedCapacity=String(l);return u});return{MixedInstancesPolicy:{InstancesDistribution:a,LaunchTemplate:{Overrides:o}}}},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:(e)=>{let{min:t,max:n,desired:r=t,scaleUpThreshold:i=70,scaleDownThreshold:s=30,cooldownSeconds:a=300,targetMetric:o="cpu"}=e,c={cpu:"ASGAverageCPUUtilization",memory:"ASGAverageMemoryUtilization",requests:"ALBRequestCountPerTarget"};return{minSize:t,maxSize:n,desiredCapacity:r,scalingPolicies:[{policyType:"TargetTrackingScaling",targetValue:i,predefinedMetricType:c[o]||c.cpu,scaleInCooldown:a,scaleOutCooldown:a}]}},forEcs:(e)=>{let{min:t,max:n,cpuTarget:r=70,memoryTarget:i}=e,s=[{predefinedMetricType:"ECSServiceAverageCPUUtilization",targetValue:r}];if(i)s.push({predefinedMetricType:"ECSServiceAverageMemoryUtilization",targetValue:i});return{minCapacity:t,maxCapacity:n,targetTrackingPolicies:s}},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:(e)=>{let{path:t="/",interval:n=30,timeout:r=5,healthyThreshold:i=2,unhealthyThreshold:s=5,protocol:a="HTTP"}=e,o={HealthCheckIntervalSeconds:n,HealthCheckTimeoutSeconds:r,HealthyThresholdCount:i,UnhealthyThresholdCount:s};if(a!=="TCP")o.HealthCheckPath=t,o.HealthCheckProtocol=a;return o},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:(e)=>{let{certificateArn:t,targetGroupArn:n,port:r=443,sslPolicy:i="ELBSecurityPolicy-TLS13-1-2-2021-06"}=e;return{Port:r,Protocol:"HTTPS",Certificates:[{CertificateArn:t}],SslPolicy:i,DefaultActions:[{Type:"forward",TargetGroupArn:n}]}},httpRedirectListener:(e=80)=>({Port:e,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:(e)=>{let{handler:t,runtime:n="nodejs20.x",timeout:r=30,memorySize:i=256,environmentVariables:s,reservedConcurrency:a}=e,o={Handler:t,Runtime:n,Timeout:r,MemorySize:i};if(s)o.Environment={Variables:s};if(a)o.ReservedConcurrentExecutions=a;return o},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:(e)=>{let{runtime:t="bun",runtimeVersion:n="latest",webServer:r="nginx",processManager:i="systemd",enableSsl:s=!0,sslEmail:a="admin@example.com",domain:o,appPort:c=3000,installDatabaseClients:l=!1,installRedis:u=!1,extraPackages:m=[]}=e,p=`#!/bin/bash
327
327
  set -e
328
328
 
329
329
  # Update system
@@ -581,7 +581,7 @@ ufw default allow outgoing
581
581
  ${e.map((t)=>`ufw allow ${t}`).join(`
582
582
  `)}
583
583
  ufw --force enable
584
- `},Presets:{bunWithNginx:(e,t=3000)=>x.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:e,appPort:t,enableSsl:!0}),bunWithCaddy:(e,t=3000)=>x.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:e,appPort:t,enableSsl:!1}),nodeWithPm2:(e,t=3000)=>x.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:e,appPort:t,enableSsl:!0}),worker:(e="bun")=>x.UserData.generateAppServerScript({runtime:e,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(e){let{slug:t,environment:n,domain:r,instanceLogicalId:i}=e,s=S({slug:t,environment:n,resourceType:"eip"}),a=f(s),o={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:n},...r?[{Key:"Domain",Value:r}]:[]]}},c={[a]:o},l,u;if(i)u=f(`${s}-assoc`),l={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:C.GetAtt(a,"AllocationId"),InstanceId:C.Ref(i)}},c[u]=l;return{eip:o,eipAssociation:l,eipLogicalId:a,associationLogicalId:u,resources:c}}static createServerModeStack(e){let{slug:t,environment:n,vpcId:r,subnetId:i,instanceType:s="t3.small",imageId:a="ami-0f3caa1cf4417e51b",keyName:o,domain:c,userData:l,allowedPorts:u=[22,80,443],volumeSize:m=20,volumeType:p="gp3"}=e,g={},y=S({slug:t,environment:n,resourceType:"server-sg"}),h=f(y),b={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:y,GroupDescription:`Security group for ${t} server`,VpcId:r,SecurityGroupIngress:u.map((U)=>({IpProtocol:"tcp",FromPort:U,ToPort:U,CidrIp:"0.0.0.0/0",Description:`Port ${U}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:n}]}};g[h]=b;let v=S({slug:t,environment:n,resourceType:"server-role"}),T=f(v),A={Type:"AWS::IAM::Role",Properties:{RoleName:v,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:"*"}]}}]}};g[T]=A;let R=S({slug:t,environment:n,resourceType:"server-profile"}),P=f(R),E={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:R,Roles:[C.Ref(T)]}};g[P]=E;let w=S({slug:t,environment:n,resourceType:"server"}),I=f(w),D={Type:"AWS::EC2::Instance",DependsOn:[P],Properties:{ImageId:a,InstanceType:s,KeyName:o,SubnetId:i,SecurityGroupIds:[C.Ref(h)],IamInstanceProfile:C.Ref(P),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:w},{Key:"Environment",Value:n},...c?[{Key:"Domain",Value:c}]:[]]}};if(l)D.Properties.UserData=C.Base64(l);g[I]=D;let{eip:k,eipAssociation:O,eipLogicalId:j,associationLogicalId:K,resources:re}=x.createElasticIp({slug:t,environment:n,domain:c,instanceLogicalId:I});return Object.assign(g,re),{instance:D,securityGroup:b,eip:k,eipAssociation:O,instanceRole:A,instanceProfile:E,resources:g,outputs:{instanceLogicalId:I,securityGroupLogicalId:h,eipLogicalId:j,associationLogicalId:K,roleLogicalId:T,profileLogicalId:P}}}static ServerMode={webServer:(e)=>{let t=x.UserData.generateAppServerScript({runtime:e.runtime||"bun",webServer:e.webServer||"nginx",domain:e.domain,enableSsl:!0});return x.createServerModeStack({...e,userData:t,instanceType:"t3.small",allowedPorts:[22,80,443]})},workerServer:(e)=>{let t=x.UserData.generateAppServerScript({runtime:e.runtime||"bun",webServer:"none",installRedis:e.installRedis});return x.createServerModeStack({...e,userData:t,instanceType:"t3.medium",allowedPorts:[22]})},cacheServer:(e)=>x.createServerModeStack({...e,userData:`#!/bin/bash
584
+ `},Presets:{bunWithNginx:(e,t=3000)=>x.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:e,appPort:t,enableSsl:!0}),bunWithCaddy:(e,t=3000)=>x.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:e,appPort:t,enableSsl:!1}),nodeWithPm2:(e,t=3000)=>x.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:e,appPort:t,enableSsl:!0}),worker:(e="bun")=>x.UserData.generateAppServerScript({runtime:e,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(e){let{slug:t,environment:n,domain:r,instanceLogicalId:i}=e,s=S({slug:t,environment:n,resourceType:"eip"}),a=f(s),o={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:n},...r?[{Key:"Domain",Value:r}]:[]]}},c={[a]:o},l,u;if(i)u=f(`${s}-assoc`),l={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:v.GetAtt(a,"AllocationId"),InstanceId:v.Ref(i)}},c[u]=l;return{eip:o,eipAssociation:l,eipLogicalId:a,associationLogicalId:u,resources:c}}static createServerModeStack(e){let{slug:t,environment:n,vpcId:r,subnetId:i,instanceType:s="t3.small",imageId:a="ami-0f3caa1cf4417e51b",keyName:o,domain:c,userData:l,allowedPorts:u=[22,80,443],volumeSize:m=20,volumeType:p="gp3"}=e,g={},y=S({slug:t,environment:n,resourceType:"server-sg"}),h=f(y),b={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:y,GroupDescription:`Security group for ${t} server`,VpcId:r,SecurityGroupIngress:u.map((F)=>({IpProtocol:"tcp",FromPort:F,ToPort:F,CidrIp:"0.0.0.0/0",Description:`Port ${F}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:n}]}};g[h]=b;let C=S({slug:t,environment:n,resourceType:"server-role"}),T=f(C),A={Type:"AWS::IAM::Role",Properties:{RoleName:C,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:"*"}]}}]}};g[T]=A;let R=S({slug:t,environment:n,resourceType:"server-profile"}),P=f(R),E={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:R,Roles:[v.Ref(T)]}};g[P]=E;let w=S({slug:t,environment:n,resourceType:"server"}),I=f(w),D={Type:"AWS::EC2::Instance",DependsOn:[P],Properties:{ImageId:a,InstanceType:s,KeyName:o,SubnetId:i,SecurityGroupIds:[v.Ref(h)],IamInstanceProfile:v.Ref(P),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:w},{Key:"Environment",Value:n},...c?[{Key:"Domain",Value:c}]:[]]}};if(l)D.Properties.UserData=v.Base64(l);g[I]=D;let{eip:k,eipAssociation:O,eipLogicalId:ne,associationLogicalId:_,resources:q}=x.createElasticIp({slug:t,environment:n,domain:c,instanceLogicalId:I});return Object.assign(g,q),{instance:D,securityGroup:b,eip:k,eipAssociation:O,instanceRole:A,instanceProfile:E,resources:g,outputs:{instanceLogicalId:I,securityGroupLogicalId:h,eipLogicalId:ne,associationLogicalId:_,roleLogicalId:T,profileLogicalId:P}}}static ServerMode={webServer:(e)=>{let t=x.UserData.generateAppServerScript({runtime:e.runtime||"bun",webServer:e.webServer||"nginx",domain:e.domain,enableSsl:!0});return x.createServerModeStack({...e,userData:t,instanceType:"t3.small",allowedPorts:[22,80,443]})},workerServer:(e)=>{let t=x.UserData.generateAppServerScript({runtime:e.runtime||"bun",webServer:"none",installRedis:e.installRedis});return x.createServerModeStack({...e,userData:t,instanceType:"t3.medium",allowedPorts:[22]})},cacheServer:(e)=>x.createServerModeStack({...e,userData:`#!/bin/bash
585
585
  set -e
586
586
  apt-get update && apt-get upgrade -y
587
587
  apt-get install -y redis-server
@@ -589,7 +589,7 @@ sed -i 's/bind 127.0.0.1/bind 0.0.0.0/' /etc/redis/redis.conf
589
589
  systemctl enable redis-server
590
590
  systemctl restart redis-server
591
591
  echo "Redis server setup complete!"
592
- `,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class B{static createVpc(e){let{slug:t,environment:n,cidr:r="10.0.0.0/16",enableDnsHostnames:i=!0,enableDnsSupport:s=!0}=e,a=S({slug:t,environment:n,resourceType:"vpc"}),o=f(a);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:r,EnableDnsHostnames:i,EnableDnsSupport:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:n}]}},logicalId:o}}static createSubnet(e){let{slug:t,environment:n,vpcId:r,type:i,cidr:s,availabilityZone:a,mapPublicIp:o=i==="public"}=e,c=S({slug:t,environment:n,resourceType:`subnet-${i}`}),l=f(`${c}-${a}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:r,CidrBlock:s,AvailabilityZone:a,MapPublicIpOnLaunch:o,Tags:[{Key:"Name",Value:`${c}-${a}`},{Key:"Environment",Value:n},{Key:"Type",Value:i}]}},logicalId:l}}static createInternetGateway(e,t){let n=S({slug:e,environment:t,resourceType:"igw"}),r=f(n);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:n},{Key:"Environment",Value:t}]}},logicalId:r}}static attachInternetGateway(e,t){let n=f(`${e}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:C.Ref(e),InternetGatewayId:C.Ref(t)}},logicalId:n}}static createEip(e,t){let n=S({slug:e,environment:t,resourceType:"eip"}),r=f(n);return{eip:{Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:n},{Key:"Environment",Value:t}]}},logicalId:r}}static createNatGateway(e,t){let{slug:n,environment:r,subnetId:i}=e,s=S({slug:n,environment:r,resourceType:"nat"}),a=f(s);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:C.GetAtt(t,"AllocationId"),SubnetId:i,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:a}}static createRouteTable(e,t,n,r){let i=S({slug:e,environment:t,resourceType:`rt-${r}`}),s=f(i);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:C.Ref(n),Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:t},{Key:"Type",Value:r}]}},logicalId:s}}static createRoute(e,t,n){let r=f(`${e}-route-${n.type}`),i={Type:"AWS::EC2::Route",Properties:{RouteTableId:C.Ref(e),DestinationCidrBlock:t}};if(n.type==="igw")i.Properties.GatewayId=C.Ref(n.logicalId);else if(n.type==="nat")i.Properties.NatGatewayId=C.Ref(n.logicalId);else if(n.type==="instance")i.Properties.InstanceId=C.Ref(n.logicalId);return{route:i,logicalId:r}}static associateSubnetWithRouteTable(e,t){let n=f(`${e}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:C.Ref(e),RouteTableId:C.Ref(t)}},logicalId:n}}static enableFlowLogs(e){let{slug:t,environment:n,resourceId:r,resourceType:i,trafficType:s="ALL",logGroupName:a}=e,o=S({slug:t,environment:n,resourceType:"flowlog"}),c=f(o);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:i,ResourceIds:[r],TrafficType:s,LogDestinationType:"cloud-watch-logs",LogGroupName:a||`/aws/vpc/${t}-${n}`,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}},logicalId:c}}static calculateSubnetCidrs(e,t,n=3){let[r,i]=e.split("/"),s=Number.parseInt(i,10),a=Math.ceil(Math.log2(t*n)),o=s+a;if(o>28)throw Error("VPC CIDR is too small to accommodate requested subnets");let[c,l,u,m]=r.split(".").map(Number),p=(c<<24)+(l<<16)+(u<<8)+m,g=2**(32-o),y=[];for(let h=0;h<t*n;h++){let b=p+h*g,v=[b>>>24&255,b>>>16&255,b>>>8&255,b&255].join(".");y.push(`${v}/${o}`)}return y}static getAvailabilityZones(e,t){return["a","b","c","d","e","f"].slice(0,t).map((r)=>`${e}${r}`)}static createMultiAzNetwork(e){let{slug:t,environment:n,region:r,cidr:i="10.0.0.0/16",zones:s=3,enableNatGateway:a=!1,singleNatGateway:o=!1,enableFlowLogs:c=!1}=e,l={},u=[],m=[],p=[],{vpc:g,logicalId:y}=B.createVpc({slug:t,environment:n,cidr:i});l[y]=g;let{internetGateway:h,logicalId:b}=B.createInternetGateway(t,n);l[b]=h;let{attachment:v,logicalId:T}=B.attachInternetGateway(y,b);l[T]=v;let{routeTable:A,logicalId:R}=B.createRouteTable(t,n,y,"public");l[R]=A;let{route:P,logicalId:E}=B.createRoute(R,"0.0.0.0/0",{type:"igw",logicalId:b});P.DependsOn=T,l[E]=P;let w=B.calculateSubnetCidrs(i,s,2),I=B.getAvailabilityZones(r,s),D=[];for(let k=0;k<s;k++){let O=I[k],j=w[k*2],K=w[k*2+1],{subnet:re,logicalId:U}=B.createSubnet({slug:t,environment:n,vpcId:C.Ref(y),type:"public",cidr:j,availabilityZone:O});l[U]=re,u.push(U);let{association:Pe,logicalId:qe}=B.associateSubnetWithRouteTable(U,R);l[qe]=Pe;let{subnet:Bt,logicalId:ue}=B.createSubnet({slug:t,environment:n,vpcId:C.Ref(y),type:"private",cidr:K,availabilityZone:O});if(l[ue]=Bt,m.push(ue),a&&(!o||k===0)){let{eip:se,logicalId:de}=B.createEip(`${t}-${O}`,n);l[de]=se;let{natGateway:Ee,logicalId:me}=B.createNatGateway({slug:`${t}-${O}`,environment:n,subnetId:C.Ref(U)},de);Ee.DependsOn=T,l[me]=Ee,p.push(me);let{routeTable:Se,logicalId:Le}=B.createRouteTable(`${t}-${O}`,n,y,"private");l[Le]=Se,D.push(Le);let{route:ze,logicalId:N}=B.createRoute(Le,"0.0.0.0/0",{type:"nat",logicalId:me});l[N]=ze;let{association:M,logicalId:F}=B.associateSubnetWithRouteTable(ue,Le);l[F]=M}else if(a&&o&&k>0){let{association:se,logicalId:de}=B.associateSubnetWithRouteTable(ue,D[0]);l[de]=se}else{let{routeTable:se,logicalId:de}=B.createRouteTable(`${t}-${O}-isolated`,n,y,"private");l[de]=se;let{association:Ee,logicalId:me}=B.associateSubnetWithRouteTable(ue,de);l[me]=Ee}}if(c){let{flowLog:k,logicalId:O}=B.enableFlowLogs({slug:t,environment:n,resourceId:C.Ref(y),resourceType:"VPC"});l[O]=k}return{resources:l,outputs:{vpcId:y,publicSubnetIds:u,privateSubnetIds:m,natGatewayIds:p.length>0?p:void 0}}}static NatGatewayCostWarning=`
592
+ `,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class B{static createVpc(e){let{slug:t,environment:n,cidr:r="10.0.0.0/16",enableDnsHostnames:i=!0,enableDnsSupport:s=!0}=e,a=S({slug:t,environment:n,resourceType:"vpc"}),o=f(a);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:r,EnableDnsHostnames:i,EnableDnsSupport:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:n}]}},logicalId:o}}static createSubnet(e){let{slug:t,environment:n,vpcId:r,type:i,cidr:s,availabilityZone:a,mapPublicIp:o=i==="public"}=e,c=S({slug:t,environment:n,resourceType:`subnet-${i}`}),l=f(`${c}-${a}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:r,CidrBlock:s,AvailabilityZone:a,MapPublicIpOnLaunch:o,Tags:[{Key:"Name",Value:`${c}-${a}`},{Key:"Environment",Value:n},{Key:"Type",Value:i}]}},logicalId:l}}static createInternetGateway(e,t){let n=S({slug:e,environment:t,resourceType:"igw"}),r=f(n);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:n},{Key:"Environment",Value:t}]}},logicalId:r}}static attachInternetGateway(e,t){let n=f(`${e}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:v.Ref(e),InternetGatewayId:v.Ref(t)}},logicalId:n}}static createEip(e,t){let n=S({slug:e,environment:t,resourceType:"eip"}),r=f(n);return{eip:{Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:n},{Key:"Environment",Value:t}]}},logicalId:r}}static createNatGateway(e,t){let{slug:n,environment:r,subnetId:i}=e,s=S({slug:n,environment:r,resourceType:"nat"}),a=f(s);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:v.GetAtt(t,"AllocationId"),SubnetId:i,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:a}}static createRouteTable(e,t,n,r){let i=S({slug:e,environment:t,resourceType:`rt-${r}`}),s=f(i);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:v.Ref(n),Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:t},{Key:"Type",Value:r}]}},logicalId:s}}static createRoute(e,t,n){let r=f(`${e}-route-${n.type}`),i={Type:"AWS::EC2::Route",Properties:{RouteTableId:v.Ref(e),DestinationCidrBlock:t}};if(n.type==="igw")i.Properties.GatewayId=v.Ref(n.logicalId);else if(n.type==="nat")i.Properties.NatGatewayId=v.Ref(n.logicalId);else if(n.type==="instance")i.Properties.InstanceId=v.Ref(n.logicalId);return{route:i,logicalId:r}}static associateSubnetWithRouteTable(e,t){let n=f(`${e}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:v.Ref(e),RouteTableId:v.Ref(t)}},logicalId:n}}static enableFlowLogs(e){let{slug:t,environment:n,resourceId:r,resourceType:i,trafficType:s="ALL",logGroupName:a}=e,o=S({slug:t,environment:n,resourceType:"flowlog"}),c=f(o);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:i,ResourceIds:[r],TrafficType:s,LogDestinationType:"cloud-watch-logs",LogGroupName:a||`/aws/vpc/${t}-${n}`,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}},logicalId:c}}static calculateSubnetCidrs(e,t,n=3){let[r,i]=e.split("/"),s=Number.parseInt(i,10),a=Math.ceil(Math.log2(t*n)),o=s+a;if(o>28)throw Error("VPC CIDR is too small to accommodate requested subnets");let[c,l,u,m]=r.split(".").map(Number),p=(c<<24)+(l<<16)+(u<<8)+m,g=2**(32-o),y=[];for(let h=0;h<t*n;h++){let b=p+h*g,C=[b>>>24&255,b>>>16&255,b>>>8&255,b&255].join(".");y.push(`${C}/${o}`)}return y}static getAvailabilityZones(e,t){return["a","b","c","d","e","f"].slice(0,t).map((r)=>`${e}${r}`)}static createMultiAzNetwork(e){let{slug:t,environment:n,region:r,cidr:i="10.0.0.0/16",zones:s=3,enableNatGateway:a=!1,singleNatGateway:o=!1,enableFlowLogs:c=!1}=e,l={},u=[],m=[],p=[],{vpc:g,logicalId:y}=B.createVpc({slug:t,environment:n,cidr:i});l[y]=g;let{internetGateway:h,logicalId:b}=B.createInternetGateway(t,n);l[b]=h;let{attachment:C,logicalId:T}=B.attachInternetGateway(y,b);l[T]=C;let{routeTable:A,logicalId:R}=B.createRouteTable(t,n,y,"public");l[R]=A;let{route:P,logicalId:E}=B.createRoute(R,"0.0.0.0/0",{type:"igw",logicalId:b});P.DependsOn=T,l[E]=P;let w=B.calculateSubnetCidrs(i,s,2),I=B.getAvailabilityZones(r,s),D=[];for(let k=0;k<s;k++){let O=I[k],ne=w[k*2],_=w[k*2+1],{subnet:q,logicalId:F}=B.createSubnet({slug:t,environment:n,vpcId:v.Ref(y),type:"public",cidr:ne,availabilityZone:O});l[F]=q,u.push(F);let{association:K,logicalId:de}=B.associateSubnetWithRouteTable(F,R);l[de]=K;let{subnet:Oe,logicalId:me}=B.createSubnet({slug:t,environment:n,vpcId:v.Ref(y),type:"private",cidr:_,availabilityZone:O});if(l[me]=Oe,m.push(me),a&&(!o||k===0)){let{eip:ae,logicalId:pe}=B.createEip(`${t}-${O}`,n);l[pe]=ae;let{natGateway:we,logicalId:ge}=B.createNatGateway({slug:`${t}-${O}`,environment:n,subnetId:v.Ref(F)},pe);we.DependsOn=T,l[ge]=we,p.push(ge);let{routeTable:Ce,logicalId:$e}=B.createRouteTable(`${t}-${O}`,n,y,"private");l[$e]=Ce,D.push($e);let{route:Qe,logicalId:N}=B.createRoute($e,"0.0.0.0/0",{type:"nat",logicalId:ge});l[N]=Qe;let{association:M,logicalId:G}=B.associateSubnetWithRouteTable(me,$e);l[G]=M}else if(a&&o&&k>0){let{association:ae,logicalId:pe}=B.associateSubnetWithRouteTable(me,D[0]);l[pe]=ae}else{let{routeTable:ae,logicalId:pe}=B.createRouteTable(`${t}-${O}-isolated`,n,y,"private");l[pe]=ae;let{association:we,logicalId:ge}=B.associateSubnetWithRouteTable(me,pe);l[ge]=we}}if(c){let{flowLog:k,logicalId:O}=B.enableFlowLogs({slug:t,environment:n,resourceId:v.Ref(y),resourceType:"VPC"});l[O]=k}return{resources:l,outputs:{vpcId:y,publicSubnetIds:u,privateSubnetIds:m,natGatewayIds:p.length>0?p:void 0}}}static NatGatewayCostWarning=`
593
593
  ⚠️ NAT Gateway Cost Warning:
594
594
  - Each NAT Gateway costs approximately $32-45/month (hourly charges)
595
595
  - Data processing charges: $0.045/GB processed
@@ -597,7 +597,7 @@ echo "Redis server setup complete!"
597
597
  - Using a single NAT Gateway (singleNatGateway: true)
598
598
  - Using NAT Instances instead (cheaper but requires management)
599
599
  - Disabling NAT entirely for isolated private subnets
600
- `}class Xe{static createFileSystem(e){let{slug:t,environment:n,encrypted:r=!0,kmsKeyId:i,performanceMode:s="generalPurpose",throughputMode:a="bursting",provisionedThroughput:o,enableBackup:c=!0}=e,l=S({slug:t,environment:n,resourceType:"efs"}),u=f(l),m={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:r,PerformanceMode:s,ThroughputMode:a,FileSystemTags:[{Key:"Name",Value:l},{Key:"Environment",Value:n}]}};if(i)m.Properties.KmsKeyId=i;if(a==="provisioned"&&o)m.Properties.ProvisionedThroughputInMibps=o;if(c)m.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:m,logicalId:u}}static createMountTarget(e,t){let{slug:n,environment:r,subnetId:i,securityGroups:s,ipAddress:a}=t,o=S({slug:n,environment:r,resourceType:"efs-mt"}),c=f(`${o}-${i}`),l={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:C.Ref(e),SubnetId:i,SecurityGroups:s}};if(a)l.Properties.IpAddress=a;return{mountTarget:l,logicalId:c}}static createAccessPoint(e,t){let{slug:n,environment:r,path:i="/",uid:s="1000",gid:a="1000",permissions:o="755"}=t,c=S({slug:n,environment:r,resourceType:"efs-ap"}),l=f(`${c}-${i.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:C.Ref(e),PosixUser:{Uid:s,Gid:a},RootDirectory:{Path:i,CreationInfo:{OwnerUid:s,OwnerGid:a,Permissions:o}},AccessPointTags:[{Key:"Name",Value:`${c}-${i}`},{Key:"Environment",Value:r}]}},logicalId:l}}static setLifecyclePolicy(e,t){let{transitionToIA:n,transitionToPrimary:r=!1}=t;if(!e.Properties)e.Properties={};if(e.Properties.LifecyclePolicies=[],n){let i=`AFTER_${n}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:i})}if(r)e.Properties.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"});return e}static enableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"ENABLED"},e}static disableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"DISABLED"},e}static setProvisionedThroughput(e,t){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="provisioned",e.Properties.ProvisionedThroughputInMibps=t,e}static setElasticThroughput(e){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="elastic",e}static enableMaxIO(e){if(!e.Properties)e.Properties={};return e.Properties.PerformanceMode="maxIO",e}static createEfsSecurityGroup(e){let{slug:t,environment:n,vpcId:r,sourceSecurityGroupIds:i=[],sourceCidrBlocks:s=[],description:a}=e,o=S({slug:t,environment:n,resourceType:"efs-sg"}),c=f(o),l=[];for(let m of i)l.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:m,Description:"NFS from security group"});for(let m of s)l.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:m,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:o,GroupDescription:a||`Security group for EFS mount targets - ${t} ${n}`,VpcId:r,SecurityGroupIngress:l,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}},logicalId:c}}static createMultiAzMountTargets(e,t){let{slug:n,environment:r,subnetIds:i,securityGroupId:s}=t,a=[],o=[];for(let c=0;c<i.length;c++){let l=i[c],u=S({slug:n,environment:r,resourceType:"efs-mt"}),m=f(`${u}-az${c+1}`),p={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:C.Ref(e),SubnetId:l,SecurityGroups:[s]}};a.push(p),o.push(m)}return{mountTargets:a,logicalIds:o}}static createCompleteFileSystem(e){let{slug:t,environment:n,vpcId:r,subnetIds:i,sourceSecurityGroupIds:s=[],encrypted:a=!0,performanceMode:o="generalPurpose",throughputMode:c="elastic",enableBackup:l=!0,transitionToIA:u}=e,m={},{fileSystem:p,logicalId:g}=Xe.createFileSystem({slug:t,environment:n,encrypted:a,performanceMode:o,throughputMode:c,enableBackup:l});if(u)Xe.setLifecyclePolicy(p,{transitionToIA:u,transitionToPrimary:!0});m[g]=p;let{securityGroup:y,logicalId:h}=Xe.createEfsSecurityGroup({slug:t,environment:n,vpcId:r,sourceSecurityGroupIds:s});m[h]=y;let{mountTargets:b,logicalIds:v}=Xe.createMultiAzMountTargets(g,{slug:t,environment:n,subnetIds:i,securityGroupId:C.Ref(h)});for(let T=0;T<b.length;T++)m[v[T]]=b[T];return{resources:m,outputs:{fileSystemId:g,securityGroupId:h,mountTargetIds:v}}}}class G{static verifyDomain(e){let{domain:t,slug:n,environment:r,enableDkim:i=!0,dkimKeyLength:s="RSA_2048_BIT"}=e,a=S({slug:n,environment:r,resourceType:"ses-identity"}),o=f(`${a}-${t.replace(/\./g,"")}`),c={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:t,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(i)c.Properties.DkimSigningAttributes={NextSigningKeyLength:s};return{emailIdentity:c,logicalId:o}}static createDkimRecords(e,t,n){let r=[];for(let i=0;i<t.length;i++){let s=t[i],a=f(`dkim-${e.replace(/\./g,"")}-${i+1}`),o={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:`${s}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${s}.dkim.amazonses.com`]}};r.push({record:o,logicalId:a})}return r}static createConfigurationSet(e){let{slug:t,environment:n,name:r,reputationMetrics:i=!0,sendingEnabled:s=!0,suppressBounces:a=!0,suppressComplaints:o=!0}=e,c=r||S({slug:t,environment:n,resourceType:"ses-config"}),l=f(c),u=[];if(a)u.push("BOUNCE");if(o)u.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:c,ReputationOptions:{ReputationMetricsEnabled:i},SendingOptions:{SendingEnabled:s},SuppressionOptions:{SuppressedReasons:u}}},logicalId:l}}static createReceiptRuleSet(e){let{slug:t,environment:n,name:r}=e,i=r||S({slug:t,environment:n,resourceType:"ses-ruleset"}),s=f(i);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:i}},logicalId:s}}static createReceiptRule(e,t){let{slug:n,environment:r,ruleSetName:i,recipients:s,enabled:a=!0,scanEnabled:o=!0,tlsPolicy:c="Require",s3Action:l,lambdaAction:u,snsAction:m}=t,p=S({slug:n,environment:r,resourceType:"ses-rule"}),g=f(p),y=[];if(l)y.push({S3Action:{BucketName:l.bucketName,ObjectKeyPrefix:l.prefix,KmsKeyArn:l.kmsKeyArn}});if(u)y.push({LambdaAction:{FunctionArn:u.functionArn,InvocationType:u.invocationType||"Event"}});if(m)y.push({SNSAction:{TopicArn:m.topicArn,Encoding:m.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:i,Rule:{Name:p,Enabled:a,ScanEnabled:o,TlsPolicy:c,Recipients:s,Actions:y.length>0?y:void 0}}},logicalId:g}}static createMxRecord(e,t,n){let r=f(`mx-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t,Name:e,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${n}.amazonaws.com`]}},logicalId:r}}static createVerificationRecord(e,t,n){let r=f(`verification-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:`_amazonses.${e}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${t}"`]}},logicalId:r}}static getSmtpEndpoint(e){return`email-smtp.${e}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(e,t,n){let{includeDomains:r=[],softFail:i=!1}=n||{},s=f(`spf-${e.replace(/\./g,"")}`),a="v=spf1 include:amazonses.com";for(let c of r)a+=` include:${c}`;return a+=i?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${a}"`]}},logicalId:s}}static createDmarcRecord(e,t,n){let{policy:r="none",subdomainPolicy:i,percentage:s=100,reportingEmail:a,forensicEmail:o}=n||{},c=f(`dmarc-${e.replace(/\./g,"")}`),l=`v=DMARC1; p=${r}; pct=${s}`;if(i)l+=`; sp=${i}`;if(a)l+=`; rua=mailto:${a}`;if(o)l+=`; ruf=mailto:${o}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t,Name:`_dmarc.${e}`,Type:"TXT",TTL:300,ResourceRecords:[`"${l}"`]}},logicalId:c}}static createInboundEmailSetup(e){let{slug:t,environment:n,domain:r,s3BucketName:i,s3KeyPrefix:s="inbound/",region:a,hostedZoneId:o,lambdaFunctionArn:c,snsTopicArn:l}=e,u={},{ruleSet:m,logicalId:p}=G.createReceiptRuleSet({slug:t,environment:n});u[p]=m;let{receiptRule:g,logicalId:y}=G.createReceiptRule(p,{slug:t,environment:n,ruleSetName:m.Properties.RuleSetName||`${t}-${n}-receipt-rule-set`,recipients:[r],s3Action:{bucketName:i,prefix:s},lambdaAction:c?{functionArn:c,invocationType:"Event"}:void 0,snsAction:l?{topicArn:l}:void 0});u[y]=g;let{record:h,logicalId:b}=G.createMxRecord(r,o,a);return u[b]=h,{resources:u,outputs:{ruleSetLogicalId:p,ruleLogicalId:y,mxRecordLogicalId:b}}}static createCompleteDomainSetup(e){let{slug:t,environment:n,domain:r,hostedZoneId:i,region:s,enableInbound:a=!1,inboundS3Bucket:o,dmarcReportingEmail:c}=e,l={},{emailIdentity:u,logicalId:m}=G.verifyDomain({domain:r,slug:t,environment:n});l[m]=u;let{configurationSet:p,logicalId:g}=G.createConfigurationSet({slug:t,environment:n});l[g]=p;let{record:y,logicalId:h}=G.createSpfRecord(r,i);l[h]=y;let{record:b,logicalId:v}=G.createDmarcRecord(r,i,{policy:"none",reportingEmail:c||`dmarc-reports@${r}`});if(l[v]=b,a&&o){let T=G.createInboundEmailSetup({slug:t,environment:n,domain:r,s3BucketName:o,region:s,hostedZoneId:i});Object.assign(l,T.resources)}return{resources:l,outputs:{identityLogicalId:m,configSetLogicalId:g}}}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(e){return e in G.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:t,environment:n,s3BucketArn:r,sesIdentityArn:i}=e,s=S({slug:t,environment:n,resourceType:"email-lambda-role"}),a=f(s),o=f(`${s}-policy`),c={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"],Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:n}]}},l=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[r,`${r}/*`]}];if(i)l.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:i});let u={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${s}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:l},Roles:[C.Ref(a)]}};return{role:c,policy:u,roleLogicalId:a,policyLogicalId:o}}static createOutboundEmailLambda(e){let{slug:t,environment:n,roleArn:r,domain:i,configurationSetName:s,timeout:a=30,memorySize:o=256}=e,c=S({slug:t,environment:n,resourceType:"outbound-email"}),l=f(c);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:c,Runtime:"nodejs20.x",Handler:"index.handler",Role:r,Timeout:a,MemorySize:o,Environment:{Variables:{DOMAIN:i,CONFIGURATION_SET:s||""}},Code:{ZipFile:G.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:n},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:l}}static createInboundEmailLambda(e){let{slug:t,environment:n,roleArn:r,s3BucketName:i,organizedPrefix:s="organized/",timeout:a=60,memorySize:o=512}=e,c=S({slug:t,environment:n,resourceType:"inbound-email"}),l=f(c),u=f(`${c}-permission`),m={Type:"AWS::Lambda::Function",Properties:{FunctionName:c,Runtime:"nodejs20.x",Handler:"index.handler",Role:r,Timeout:a,MemorySize:o,Environment:{Variables:{S3_BUCKET:i,ORGANIZED_PREFIX:s}},Code:{ZipFile:G.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:n},{Key:"Purpose",Value:"InboundEmail"}]}},p={Type:"AWS::Lambda::Permission",Properties:{FunctionName:C.Ref(l),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:C.Ref("AWS::AccountId")}};return{function:m,permission:p,logicalId:l,permissionLogicalId:u}}static createEmailConversionLambda(e){let{slug:t,environment:n,roleArn:r,s3BucketName:i,convertedPrefix:s="converted/",timeout:a=60,memorySize:o=512}=e,c=S({slug:t,environment:n,resourceType:"email-conversion"}),l=f(c);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:c,Runtime:"nodejs20.x",Handler:"index.handler",Role:r,Timeout:a,MemorySize:o,Environment:{Variables:{S3_BUCKET:i,CONVERTED_PREFIX:s}},Code:{ZipFile:G.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:n},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:l}}static createEmailBucketNotification(e){let{lambdaArn:t,prefix:n="inbound/",suffix:r,events:i}=e,s=i??["s3:ObjectCreated:*"],a={};if(n||r){if(a.S3Key={Rules:[]},n)a.S3Key.Rules.push({Name:"prefix",Value:n});if(r)a.S3Key.Rules.push({Name:"suffix",Value:r})}return{notificationConfiguration:{LambdaConfigurations:[{Event:s[0],Function:t,Filter:Object.keys(a).length>0?a:void 0}]}}}static createS3LambdaPermission(e){let{slug:t,environment:n,lambdaLogicalId:r,s3BucketArn:i}=e,s=S({slug:t,environment:n,resourceType:"s3-lambda-permission"}),a=f(s);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:C.Ref(r),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:i}},logicalId:a}}static createEmailProcessingStack(e){let{slug:t,environment:n,domain:r,s3BucketName:i,s3BucketArn:s,configurationSetName:a,enableInbound:o=!0,enableConversion:c=!0}=e,l={},{role:u,policy:m,roleLogicalId:p,policyLogicalId:g}=G.createEmailLambdaRole({slug:t,environment:n,s3BucketArn:s,sesIdentityArn:`arn:aws:ses:*:*:identity/${r}`});l[p]=u,l[g]=m;let{function:y,logicalId:h}=G.createOutboundEmailLambda({slug:t,environment:n,roleArn:C.GetAtt(p,"Arn"),domain:r,configurationSetName:a});l[h]=y;let b={roleLogicalId:p,outboundLambdaLogicalId:h};if(o){let{function:v,permission:T,logicalId:A,permissionLogicalId:R}=G.createInboundEmailLambda({slug:t,environment:n,roleArn:C.GetAtt(p,"Arn"),s3BucketName:i});l[A]=v,l[R]=T;let{permission:P,logicalId:E}=G.createS3LambdaPermission({slug:t,environment:n,lambdaLogicalId:A,s3BucketArn:s});l[E]=P,b.inboundLambdaLogicalId=A}if(c){let{function:v,logicalId:T}=G.createEmailConversionLambda({slug:t,environment:n,roleArn:C.GetAtt(p,"Arn"),s3BucketName:i});l[T]=v,b.conversionLambdaLogicalId=T}return{resources:l,outputs:b}}static LambdaCode={outboundEmail:`
600
+ `}class et{static createFileSystem(e){let{slug:t,environment:n,encrypted:r=!0,kmsKeyId:i,performanceMode:s="generalPurpose",throughputMode:a="bursting",provisionedThroughput:o,enableBackup:c=!0}=e,l=S({slug:t,environment:n,resourceType:"efs"}),u=f(l),m={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:r,PerformanceMode:s,ThroughputMode:a,FileSystemTags:[{Key:"Name",Value:l},{Key:"Environment",Value:n}]}};if(i)m.Properties.KmsKeyId=i;if(a==="provisioned"&&o)m.Properties.ProvisionedThroughputInMibps=o;if(c)m.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:m,logicalId:u}}static createMountTarget(e,t){let{slug:n,environment:r,subnetId:i,securityGroups:s,ipAddress:a}=t,o=S({slug:n,environment:r,resourceType:"efs-mt"}),c=f(`${o}-${i}`),l={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:v.Ref(e),SubnetId:i,SecurityGroups:s}};if(a)l.Properties.IpAddress=a;return{mountTarget:l,logicalId:c}}static createAccessPoint(e,t){let{slug:n,environment:r,path:i="/",uid:s="1000",gid:a="1000",permissions:o="755"}=t,c=S({slug:n,environment:r,resourceType:"efs-ap"}),l=f(`${c}-${i.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:v.Ref(e),PosixUser:{Uid:s,Gid:a},RootDirectory:{Path:i,CreationInfo:{OwnerUid:s,OwnerGid:a,Permissions:o}},AccessPointTags:[{Key:"Name",Value:`${c}-${i}`},{Key:"Environment",Value:r}]}},logicalId:l}}static setLifecyclePolicy(e,t){let{transitionToIA:n,transitionToPrimary:r=!1}=t;if(!e.Properties)e.Properties={};if(e.Properties.LifecyclePolicies=[],n){let i=`AFTER_${n}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:i})}if(r)e.Properties.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"});return e}static enableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"ENABLED"},e}static disableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"DISABLED"},e}static setProvisionedThroughput(e,t){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="provisioned",e.Properties.ProvisionedThroughputInMibps=t,e}static setElasticThroughput(e){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="elastic",e}static enableMaxIO(e){if(!e.Properties)e.Properties={};return e.Properties.PerformanceMode="maxIO",e}static createEfsSecurityGroup(e){let{slug:t,environment:n,vpcId:r,sourceSecurityGroupIds:i=[],sourceCidrBlocks:s=[],description:a}=e,o=S({slug:t,environment:n,resourceType:"efs-sg"}),c=f(o),l=[];for(let m of i)l.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:m,Description:"NFS from security group"});for(let m of s)l.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:m,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:o,GroupDescription:a||`Security group for EFS mount targets - ${t} ${n}`,VpcId:r,SecurityGroupIngress:l,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}},logicalId:c}}static createMultiAzMountTargets(e,t){let{slug:n,environment:r,subnetIds:i,securityGroupId:s}=t,a=[],o=[];for(let c=0;c<i.length;c++){let l=i[c],u=S({slug:n,environment:r,resourceType:"efs-mt"}),m=f(`${u}-az${c+1}`),p={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:v.Ref(e),SubnetId:l,SecurityGroups:[s]}};a.push(p),o.push(m)}return{mountTargets:a,logicalIds:o}}static createCompleteFileSystem(e){let{slug:t,environment:n,vpcId:r,subnetIds:i,sourceSecurityGroupIds:s=[],encrypted:a=!0,performanceMode:o="generalPurpose",throughputMode:c="elastic",enableBackup:l=!0,transitionToIA:u}=e,m={},{fileSystem:p,logicalId:g}=et.createFileSystem({slug:t,environment:n,encrypted:a,performanceMode:o,throughputMode:c,enableBackup:l});if(u)et.setLifecyclePolicy(p,{transitionToIA:u,transitionToPrimary:!0});m[g]=p;let{securityGroup:y,logicalId:h}=et.createEfsSecurityGroup({slug:t,environment:n,vpcId:r,sourceSecurityGroupIds:s});m[h]=y;let{mountTargets:b,logicalIds:C}=et.createMultiAzMountTargets(g,{slug:t,environment:n,subnetIds:i,securityGroupId:v.Ref(h)});for(let T=0;T<b.length;T++)m[C[T]]=b[T];return{resources:m,outputs:{fileSystemId:g,securityGroupId:h,mountTargetIds:C}}}}class W{static verifyDomain(e){let{domain:t,slug:n,environment:r,enableDkim:i=!0,dkimKeyLength:s="RSA_2048_BIT"}=e,a=S({slug:n,environment:r,resourceType:"ses-identity"}),o=f(`${a}-${t.replace(/\./g,"")}`),c={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:t,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(i)c.Properties.DkimSigningAttributes={NextSigningKeyLength:s};return{emailIdentity:c,logicalId:o}}static createDkimRecords(e,t,n){let r=[];for(let i=0;i<t.length;i++){let s=t[i],a=f(`dkim-${e.replace(/\./g,"")}-${i+1}`),o={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:`${s}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${s}.dkim.amazonses.com`]}};r.push({record:o,logicalId:a})}return r}static createConfigurationSet(e){let{slug:t,environment:n,name:r,reputationMetrics:i=!0,sendingEnabled:s=!0,suppressBounces:a=!0,suppressComplaints:o=!0}=e,c=r||S({slug:t,environment:n,resourceType:"ses-config"}),l=f(c),u=[];if(a)u.push("BOUNCE");if(o)u.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:c,ReputationOptions:{ReputationMetricsEnabled:i},SendingOptions:{SendingEnabled:s},SuppressionOptions:{SuppressedReasons:u}}},logicalId:l}}static createReceiptRuleSet(e){let{slug:t,environment:n,name:r}=e,i=r||S({slug:t,environment:n,resourceType:"ses-ruleset"}),s=f(i);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:i}},logicalId:s}}static createReceiptRule(e,t){let{slug:n,environment:r,ruleSetName:i,recipients:s,enabled:a=!0,scanEnabled:o=!0,tlsPolicy:c="Require",s3Action:l,lambdaAction:u,snsAction:m}=t,p=S({slug:n,environment:r,resourceType:"ses-rule"}),g=f(p),y=[];if(l)y.push({S3Action:{BucketName:l.bucketName,ObjectKeyPrefix:l.prefix,KmsKeyArn:l.kmsKeyArn}});if(u)y.push({LambdaAction:{FunctionArn:u.functionArn,InvocationType:u.invocationType||"Event"}});if(m)y.push({SNSAction:{TopicArn:m.topicArn,Encoding:m.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:i,Rule:{Name:p,Enabled:a,ScanEnabled:o,TlsPolicy:c,Recipients:s,Actions:y.length>0?y:void 0}}},logicalId:g}}static createMxRecord(e,t,n){let r=f(`mx-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t,Name:e,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${n}.amazonaws.com`]}},logicalId:r}}static createVerificationRecord(e,t,n){let r=f(`verification-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:`_amazonses.${e}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${t}"`]}},logicalId:r}}static getSmtpEndpoint(e){return`email-smtp.${e}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(e,t,n){let{includeDomains:r=[],softFail:i=!1}=n||{},s=f(`spf-${e.replace(/\./g,"")}`),a="v=spf1 include:amazonses.com";for(let c of r)a+=` include:${c}`;return a+=i?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${a}"`]}},logicalId:s}}static createDmarcRecord(e,t,n){let{policy:r="none",subdomainPolicy:i,percentage:s=100,reportingEmail:a,forensicEmail:o}=n||{},c=f(`dmarc-${e.replace(/\./g,"")}`),l=`v=DMARC1; p=${r}; pct=${s}`;if(i)l+=`; sp=${i}`;if(a)l+=`; rua=mailto:${a}`;if(o)l+=`; ruf=mailto:${o}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t,Name:`_dmarc.${e}`,Type:"TXT",TTL:300,ResourceRecords:[`"${l}"`]}},logicalId:c}}static createInboundEmailSetup(e){let{slug:t,environment:n,domain:r,s3BucketName:i,s3KeyPrefix:s="inbound/",region:a,hostedZoneId:o,lambdaFunctionArn:c,snsTopicArn:l}=e,u={},{ruleSet:m,logicalId:p}=W.createReceiptRuleSet({slug:t,environment:n});u[p]=m;let{receiptRule:g,logicalId:y}=W.createReceiptRule(p,{slug:t,environment:n,ruleSetName:m.Properties.RuleSetName||`${t}-${n}-receipt-rule-set`,recipients:[r],s3Action:{bucketName:i,prefix:s},lambdaAction:c?{functionArn:c,invocationType:"Event"}:void 0,snsAction:l?{topicArn:l}:void 0});u[y]=g;let{record:h,logicalId:b}=W.createMxRecord(r,o,a);return u[b]=h,{resources:u,outputs:{ruleSetLogicalId:p,ruleLogicalId:y,mxRecordLogicalId:b}}}static createCompleteDomainSetup(e){let{slug:t,environment:n,domain:r,hostedZoneId:i,region:s,enableInbound:a=!1,inboundS3Bucket:o,dmarcReportingEmail:c}=e,l={},{emailIdentity:u,logicalId:m}=W.verifyDomain({domain:r,slug:t,environment:n});l[m]=u;let{configurationSet:p,logicalId:g}=W.createConfigurationSet({slug:t,environment:n});l[g]=p;let{record:y,logicalId:h}=W.createSpfRecord(r,i);l[h]=y;let{record:b,logicalId:C}=W.createDmarcRecord(r,i,{policy:"none",reportingEmail:c||`dmarc-reports@${r}`});if(l[C]=b,a&&o){let T=W.createInboundEmailSetup({slug:t,environment:n,domain:r,s3BucketName:o,region:s,hostedZoneId:i});Object.assign(l,T.resources)}return{resources:l,outputs:{identityLogicalId:m,configSetLogicalId:g}}}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(e){return e in W.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:t,environment:n,s3BucketArn:r,sesIdentityArn:i}=e,s=S({slug:t,environment:n,resourceType:"email-lambda-role"}),a=f(s),o=f(`${s}-policy`),c={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"],Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:n}]}},l=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[r,`${r}/*`]}];if(i)l.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:i});let u={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${s}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:l},Roles:[v.Ref(a)]}};return{role:c,policy:u,roleLogicalId:a,policyLogicalId:o}}static createOutboundEmailLambda(e){let{slug:t,environment:n,roleArn:r,domain:i,configurationSetName:s,timeout:a=30,memorySize:o=256}=e,c=S({slug:t,environment:n,resourceType:"outbound-email"}),l=f(c);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:c,Runtime:"nodejs20.x",Handler:"index.handler",Role:r,Timeout:a,MemorySize:o,Environment:{Variables:{DOMAIN:i,CONFIGURATION_SET:s||""}},Code:{ZipFile:W.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:n},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:l}}static createInboundEmailLambda(e){let{slug:t,environment:n,roleArn:r,s3BucketName:i,organizedPrefix:s="organized/",timeout:a=60,memorySize:o=512}=e,c=S({slug:t,environment:n,resourceType:"inbound-email"}),l=f(c),u=f(`${c}-permission`),m={Type:"AWS::Lambda::Function",Properties:{FunctionName:c,Runtime:"nodejs20.x",Handler:"index.handler",Role:r,Timeout:a,MemorySize:o,Environment:{Variables:{S3_BUCKET:i,ORGANIZED_PREFIX:s}},Code:{ZipFile:W.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:n},{Key:"Purpose",Value:"InboundEmail"}]}},p={Type:"AWS::Lambda::Permission",Properties:{FunctionName:v.Ref(l),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:v.Ref("AWS::AccountId")}};return{function:m,permission:p,logicalId:l,permissionLogicalId:u}}static createEmailConversionLambda(e){let{slug:t,environment:n,roleArn:r,s3BucketName:i,convertedPrefix:s="converted/",timeout:a=60,memorySize:o=512}=e,c=S({slug:t,environment:n,resourceType:"email-conversion"}),l=f(c);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:c,Runtime:"nodejs20.x",Handler:"index.handler",Role:r,Timeout:a,MemorySize:o,Environment:{Variables:{S3_BUCKET:i,CONVERTED_PREFIX:s}},Code:{ZipFile:W.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:n},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:l}}static createEmailBucketNotification(e){let{lambdaArn:t,prefix:n="inbound/",suffix:r,events:i}=e,s=i??["s3:ObjectCreated:*"],a={};if(n||r){if(a.S3Key={Rules:[]},n)a.S3Key.Rules.push({Name:"prefix",Value:n});if(r)a.S3Key.Rules.push({Name:"suffix",Value:r})}return{notificationConfiguration:{LambdaConfigurations:[{Event:s[0],Function:t,Filter:Object.keys(a).length>0?a:void 0}]}}}static createS3LambdaPermission(e){let{slug:t,environment:n,lambdaLogicalId:r,s3BucketArn:i}=e,s=S({slug:t,environment:n,resourceType:"s3-lambda-permission"}),a=f(s);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:v.Ref(r),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:i}},logicalId:a}}static createEmailProcessingStack(e){let{slug:t,environment:n,domain:r,s3BucketName:i,s3BucketArn:s,configurationSetName:a,enableInbound:o=!0,enableConversion:c=!0}=e,l={},{role:u,policy:m,roleLogicalId:p,policyLogicalId:g}=W.createEmailLambdaRole({slug:t,environment:n,s3BucketArn:s,sesIdentityArn:`arn:aws:ses:*:*:identity/${r}`});l[p]=u,l[g]=m;let{function:y,logicalId:h}=W.createOutboundEmailLambda({slug:t,environment:n,roleArn:v.GetAtt(p,"Arn"),domain:r,configurationSetName:a});l[h]=y;let b={roleLogicalId:p,outboundLambdaLogicalId:h};if(o){let{function:C,permission:T,logicalId:A,permissionLogicalId:R}=W.createInboundEmailLambda({slug:t,environment:n,roleArn:v.GetAtt(p,"Arn"),s3BucketName:i});l[A]=C,l[R]=T;let{permission:P,logicalId:E}=W.createS3LambdaPermission({slug:t,environment:n,lambdaLogicalId:A,s3BucketArn:s});l[E]=P,b.inboundLambdaLogicalId=A}if(c){let{function:C,logicalId:T}=W.createEmailConversionLambda({slug:t,environment:n,roleArn:v.GetAtt(p,"Arn"),s3BucketName:i});l[T]=C,b.conversionLambdaLogicalId=T}return{resources:l,outputs:b}}static LambdaCode={outboundEmail:`
601
601
  const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
602
602
  const ses = new SESClient({});
603
603
 
@@ -1635,7 +1635,7 @@ catch (error) {
1635
1635
 
1636
1636
  return { statusCode: 200, body: 'OK' };
1637
1637
  };
1638
- `;class ye{static LambdaCode={incomingCall:jt,voicemail:mr,missedCall:dr};static createConnectInstance(e){let{slug:t,environment:n,instanceAlias:r,inboundCallsEnabled:i=!0,outboundCallsEnabled:s=!0}=e;return{[`${t}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:r,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:i,OutboundCalls:s,ContactflowLogs:!0,ContactLens:!0,AutoResolveBestVoices:!0,UseCustomTTSVoices:!1,EarlyMedia:!0}}}}}static createHoursOfOperation(e){return{[`${e.slug}HoursOfOperation`]:{Type:"AWS::Connect::HoursOfOperation",Properties:{InstanceArn:e.instanceArn,Name:e.name,TimeZone:e.timezone,Config:e.schedule.map((t)=>({Day:t.day,StartTime:{Hours:t.startHour,Minutes:t.startMinute},EndTime:{Hours:t.endHour,Minutes:t.endMinute}}))}}}}static createQueue(e){return{[`${e.slug}Queue`]:{Type:"AWS::Connect::Queue",Properties:{InstanceArn:e.instanceArn,Name:e.name,HoursOfOperationArn:e.hoursOfOperationArn,MaxContacts:e.maxContacts||10}}}}static createContactFlow(e){return{[`${e.slug}ContactFlow`]:{Type:"AWS::Connect::ContactFlow",Properties:{InstanceArn:e.instanceArn,Name:e.name,Type:e.type,Content:e.content}}}}static createBasicIvrFlow(e){let t={Version:"2019-10-30",StartAction:"greeting",Actions:[{Identifier:"greeting",Type:"MessageParticipant",Parameters:{Text:e.greeting},Transitions:{NextAction:"transfer_to_queue",Errors:[{NextAction:"disconnect"}]}},{Identifier:"transfer_to_queue",Type:"TransferToQueue",Parameters:{QueueId:e.queueArn},Transitions:{NextAction:e.voicemailLambdaArn?"voicemail":"disconnect",Errors:[{NextAction:"disconnect"}]}},...e.voicemailLambdaArn?[{Identifier:"voicemail",Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:e.voicemailLambdaArn},Transitions:{NextAction:"disconnect",Errors:[{NextAction:"disconnect"}]}}]:[],{Identifier:"disconnect",Type:"DisconnectParticipant",Parameters:{},Transitions:{}}]};return JSON.stringify(t)}static createPhoneLambdaRole(e){return{[`${e.slug}PhoneLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.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(e){return{[`${e.slug}IncomingCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:ye.LambdaCode.incomingCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createVoicemailLambda(e){return{[`${e.slug}VoicemailLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-voicemail`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:300,MemorySize:512,Code:{ZipFile:ye.LambdaCode.voicemail},Environment:{Variables:{VOICEMAIL_BUCKET:e.voicemailBucket,NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",TRANSCRIPTION_ENABLED:e.transcriptionEnabled?"true":"false"}}}}}}static createMissedCallLambda(e){return{[`${e.slug}MissedCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-missed-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:ye.LambdaCode.missedCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createCallLogTable(e){return{[`${e.slug}CallLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCompleteSetup(e){let t={},n={};Object.assign(t,ye.createPhoneLambdaRole({slug:e.slug})),Object.assign(t,ye.createCallLogTable({slug:e.slug})),t[`${e.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-phone-notifications`}},t[`${e.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let r={"Fn::GetAtt":[`${e.slug}PhoneLambdaRole`,"Arn"]},i={Ref:`${e.slug}PhoneNotificationTopic`},s={Ref:`${e.slug}CallLogTable`},a={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(t,ye.createIncomingCallLambda({slug:e.slug,roleArn:r,notificationTopicArn:i,callLogTable:s,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(t,ye.createVoicemailLambda({slug:e.slug,roleArn:r,voicemailBucket:a,notificationTopicArn:i,callLogTable:s,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(t,ye.createMissedCallLambda({slug:e.slug,roleArn:r,notificationTopicArn:i,callLogTable:s,webhookUrl:e.webhookUrl})),n[`${e.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${e.slug}PhoneNotificationTopic`}},n[`${e.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${e.slug}CallLogTable`}},n[`${e.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${e.slug}VoicemailBucket`}},{resources:t,outputs:n}}}class oe{static createQueue(e){let{slug:t,environment:n,name:r,delaySeconds:i=0,visibilityTimeout:s=30,messageRetentionPeriod:a=345600,maxMessageSize:o=262144,receiveMessageWaitTime:c=0,fifo:l=!1,contentBasedDeduplication:u=!1,encrypted:m=!0,kmsKeyId:p}=e,g=r||S({slug:t,environment:n,resourceType:"queue"}),y=l?`${g}.fifo`:g,h=f(g),b={Type:"AWS::SQS::Queue",Properties:{QueueName:y,DelaySeconds:i,MaximumMessageSize:o,MessageRetentionPeriod:a,ReceiveMessageWaitTimeSeconds:c,VisibilityTimeout:s,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:n}]}};if(l)b.Properties.FifoQueue=!0,b.Properties.ContentBasedDeduplication=u;if(m)if(p)b.Properties.KmsMasterKeyId=p;else b.Properties.SqsManagedSseEnabled=!0;return{queue:b,logicalId:h}}static createDeadLetterQueue(e,t){let{slug:n,environment:r,maxReceiveCount:i=3}=t,s=S({slug:n,environment:r,resourceType:"dlq"}),a=f(s),o={Type:"AWS::SQS::Queue",Properties:{QueueName:s,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r},{Key:"Type",Value:"DeadLetterQueue"}]}},c={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:C.GetAtt(a,"Arn"),maxReceiveCount:i}}};return{deadLetterQueue:o,updatedSourceQueue:c,deadLetterLogicalId:a}}static createSchedule(e,t){let{slug:n,environment:r,name:i,description:s,enabled:a=!0}=t,o=i||S({slug:n,environment:r,resourceType:"schedule"}),c=f(o);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:o,Description:s,ScheduleExpression:e,State:a?"ENABLED":"DISABLED",Targets:[]}},logicalId:c}}static scheduleEcsTask(e,t,n){let{slug:r,environment:i,name:s,description:a,enabled:o=!0,taskDefinitionArn:c,clusterArn:l,subnets:u,securityGroups:m=[],assignPublicIp:p=!1,taskCount:g=1,containerOverrides:y}=n,h=s||S({slug:r,environment:i,resourceType:"ecs-schedule"}),b=f(h),T={Id:"1",Arn:l,RoleArn:t,EcsParameters:{TaskDefinitionArn:c,TaskCount:g,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:u,SecurityGroups:m,AssignPublicIp:p?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(y&&y.length>0)T.Input=JSON.stringify({containerOverrides:y});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:h,Description:a||`Scheduled ECS task: ${c}`,ScheduleExpression:e,State:o?"ENABLED":"DISABLED",Targets:[T]}},logicalId:b}}static scheduleLambda(e,t){let{slug:n,environment:r,name:i,description:s,enabled:a=!0,functionArn:o,input:c}=t,l=i||S({slug:n,environment:r,resourceType:"lambda-schedule"}),u=f(l),m={Id:"1",Arn:o};if(c)m.Input=JSON.stringify(c);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:l,Description:s||`Scheduled Lambda: ${o}`,ScheduleExpression:e,State:a?"ENABLED":"DISABLED",Targets:[m]}},logicalId:u}}static scheduleSqsMessage(e,t){let{slug:n,environment:r,name:i,description:s,enabled:a=!0,queueArn:o,messageGroupId:c}=t,l=i||S({slug:n,environment:r,resourceType:"sqs-schedule"}),u=f(l),m={Id:"1",Arn:o};if(c)m.SqsParameters={MessageGroupId:c};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:l,Description:s||`Scheduled SQS message: ${o}`,ScheduleExpression:e,State:a?"ENABLED":"DISABLED",Targets:[m]}},logicalId:u}}static addTarget(e,t){if(!e.Properties.Targets)e.Properties.Targets=[];let n={Id:t.id,Arn:t.arn};if(t.roleArn)n.RoleArn=t.roleArn;if(t.input)n.Input=JSON.stringify(t.input);return e.Properties.Targets.push(n),e}static toCronExpression(e){if(e.startsWith("cron(")||e.startsWith("rate("))return e;return`cron(${e})`}static rateExpression(e,t){return`rate(${e} ${t})`}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(e){let t=e.toLowerCase().trim(),n=t.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(n){let l=parseInt(n[1],10),u=n[2].toLowerCase(),m=u.endsWith("s")&&l===1?u.slice(0,-1):u,p=!u.endsWith("s")&&l>1?`${u}s`:u;return`rate(${l} ${l===1?m:p})`}let r=t.match(/^every\s+(minute|hour|day)$/i);if(r)return`rate(1 ${r[1]})`;let i={"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(i[t])return i[t];let s=t.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(s){let l=parseInt(s[1],10),u=s[2]?.toLowerCase();if(u==="pm"&&l!==12)l+=12;else if(u==="am"&&l===12)l=0;return`cron(0 ${l} * * ? *)`}let a=t.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(a){let l=parseInt(a[1],10);return`cron(${parseInt(a[2],10)} ${l} * * ? *)`}let o={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},c=t.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(c)return`cron(0 0 ? * ${o[c[1].toLowerCase()]} *)`;return oe.toCronExpression(e)}static JobConfig={create:(e)=>{let{name:t,handler:n,retries:r=3,backoff:i="exponential",backoffDelay:s=1000,maxDelay:a=30000,timeout:o=60000,jitter:c=!0}=e;return{name:t,handler:n,retries:r,backoff:i,backoffDelay:s,maxDelay:a,timeout:o,jitter:c}},calculateDelay:(e,t)=>{let{backoff:n,backoffDelay:r,maxDelay:i,jitter:s}=t,a;switch(n){case"linear":a=r*e;break;case"exponential":a=r*2**(e-1);break;case"fixed":default:a=r}if(a=Math.min(a,i||Number.MAX_SAFE_INTEGER),s){let o=a*0.25*Math.random();a+=o}return Math.floor(a)},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(e){let{containerName:t,jobClass:n,jobData:r,environment:i={}}=e,s=[{name:"JOB_CLASS",value:n}];if(r)s.push({name:"JOB_DATA",value:JSON.stringify(r)});for(let[a,o]of Object.entries(i))s.push({name:a,value:o});return{name:t,command:["bun","run","app/Jobs/runner.ts"],environment:s}}static createScheduledJob(e){let{slug:t,environment:n,schedule:r,jobClass:i,jobData:s,taskDefinitionArn:a,clusterArn:o,subnets:c,securityGroups:l=[],roleArn:u,containerName:m="app"}=e,p=oe.rateStringToExpression(r),g=oe.createJobContainerOverride({containerName:m,jobClass:i,jobData:s});return oe.scheduleEcsTask(p,u,{slug:t,environment:n,name:`${t}-${i.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${i}`,taskDefinitionArn:a,clusterArn:o,subnets:c,securityGroups:l,containerOverrides:[g]})}static QueuePresets={highThroughput:(e,t)=>oe.createQueue({slug:e,environment:t,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,t)=>oe.createQueue({slug:e,environment:t,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,t)=>oe.createQueue({slug:e,environment:t,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,t,n=60)=>oe.createQueue({slug:e,environment:t,delaySeconds:n})}}class Ce{static async discoverJobs(e){let{projectRoot:t,jobsPath:n="app/Jobs"}=e,r=`${t}/${n}`,i=[];try{let s=await import("node:fs"),a=await import("node:path");if(!s.existsSync(r))return[];let o=s.readdirSync(r).filter((c)=>c.endsWith(".ts")&&!c.startsWith("_")&&c!=="runner.ts");for(let c of o){let l=a.join(r,c),u=c.replace(".ts",""),m=s.readFileSync(l,"utf-8"),p=Ce.parseJobMetadata(m,u,l);if(p)i.push(p)}}catch{return[]}return i}static parseJobMetadata(e,t,n){let r=e.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/schedule:\s*['"`]([^'"`]+)['"`]/),i=e.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||e.match(/enabled:\s*(true|false)/),s=e.match(/export\s+const\s+retries\s*=\s*(\d+)/)||e.match(/retries:\s*(\d+)/),a=e.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||e.match(/timeout:\s*(\d+)/),o=e.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||e.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),c=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;return{name:t,path:n,schedule:r?.[1],handler:`${t}.handle`,enabled:i?.[1]!=="false",retries:s?parseInt(s[1],10):void 0,backoff:o?.[1],timeout:a?parseInt(a[1],10):void 0,description:c?.[1]}}static async discoverActions(e){let{projectRoot:t,actionsPath:n="app/Actions"}=e,r=`${t}/${n}`,i=[];try{let s=await import("node:fs"),a=await import("node:path");if(!s.existsSync(r))return[];let o=s.readdirSync(r).filter((c)=>c.endsWith(".ts")&&!c.startsWith("_"));for(let c of o){let l=a.join(r,c),u=c.replace(".ts",""),m=s.readFileSync(l,"utf-8"),p=Ce.parseActionMetadata(m,u,l);if(p)i.push(p)}}catch{return[]}return i}static parseActionMetadata(e,t,n){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let i=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:t,path:n,handler:`${t}.handle`,description:i?.[1]}}static generateScheduledJobResources(e){let{slug:t,environment:n,jobs:r,taskDefinitionArn:i,clusterArn:s,subnets:a,securityGroups:o=[],roleArn:c,containerName:l="app"}=e,u={},m=0;for(let p of r){if(!p.schedule||!p.enabled)continue;let{rule:g,logicalId:y}=oe.createScheduledJob({slug:t,environment:n,schedule:p.schedule,jobClass:p.name,taskDefinitionArn:i,clusterArn:s,subnets:a,securityGroups:o,roleArn:c,containerName:l});u[y]=g,m++}return{rules:u,count:m}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
1638
+ `;class he{static LambdaCode={incomingCall:jt,voicemail:mr,missedCall:dr};static createConnectInstance(e){let{slug:t,environment:n,instanceAlias:r,inboundCallsEnabled:i=!0,outboundCallsEnabled:s=!0}=e;return{[`${t}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:r,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:i,OutboundCalls:s,ContactflowLogs:!0,ContactLens:!0,AutoResolveBestVoices:!0,UseCustomTTSVoices:!1,EarlyMedia:!0}}}}}static createHoursOfOperation(e){return{[`${e.slug}HoursOfOperation`]:{Type:"AWS::Connect::HoursOfOperation",Properties:{InstanceArn:e.instanceArn,Name:e.name,TimeZone:e.timezone,Config:e.schedule.map((t)=>({Day:t.day,StartTime:{Hours:t.startHour,Minutes:t.startMinute},EndTime:{Hours:t.endHour,Minutes:t.endMinute}}))}}}}static createQueue(e){return{[`${e.slug}Queue`]:{Type:"AWS::Connect::Queue",Properties:{InstanceArn:e.instanceArn,Name:e.name,HoursOfOperationArn:e.hoursOfOperationArn,MaxContacts:e.maxContacts||10}}}}static createContactFlow(e){return{[`${e.slug}ContactFlow`]:{Type:"AWS::Connect::ContactFlow",Properties:{InstanceArn:e.instanceArn,Name:e.name,Type:e.type,Content:e.content}}}}static createBasicIvrFlow(e){let t={Version:"2019-10-30",StartAction:"greeting",Actions:[{Identifier:"greeting",Type:"MessageParticipant",Parameters:{Text:e.greeting},Transitions:{NextAction:"transfer_to_queue",Errors:[{NextAction:"disconnect"}]}},{Identifier:"transfer_to_queue",Type:"TransferToQueue",Parameters:{QueueId:e.queueArn},Transitions:{NextAction:e.voicemailLambdaArn?"voicemail":"disconnect",Errors:[{NextAction:"disconnect"}]}},...e.voicemailLambdaArn?[{Identifier:"voicemail",Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:e.voicemailLambdaArn},Transitions:{NextAction:"disconnect",Errors:[{NextAction:"disconnect"}]}}]:[],{Identifier:"disconnect",Type:"DisconnectParticipant",Parameters:{},Transitions:{}}]};return JSON.stringify(t)}static createPhoneLambdaRole(e){return{[`${e.slug}PhoneLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.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(e){return{[`${e.slug}IncomingCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:he.LambdaCode.incomingCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createVoicemailLambda(e){return{[`${e.slug}VoicemailLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-voicemail`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:300,MemorySize:512,Code:{ZipFile:he.LambdaCode.voicemail},Environment:{Variables:{VOICEMAIL_BUCKET:e.voicemailBucket,NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",TRANSCRIPTION_ENABLED:e.transcriptionEnabled?"true":"false"}}}}}}static createMissedCallLambda(e){return{[`${e.slug}MissedCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-missed-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:he.LambdaCode.missedCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createCallLogTable(e){return{[`${e.slug}CallLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCompleteSetup(e){let t={},n={};Object.assign(t,he.createPhoneLambdaRole({slug:e.slug})),Object.assign(t,he.createCallLogTable({slug:e.slug})),t[`${e.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-phone-notifications`}},t[`${e.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let r={"Fn::GetAtt":[`${e.slug}PhoneLambdaRole`,"Arn"]},i={Ref:`${e.slug}PhoneNotificationTopic`},s={Ref:`${e.slug}CallLogTable`},a={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(t,he.createIncomingCallLambda({slug:e.slug,roleArn:r,notificationTopicArn:i,callLogTable:s,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(t,he.createVoicemailLambda({slug:e.slug,roleArn:r,voicemailBucket:a,notificationTopicArn:i,callLogTable:s,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(t,he.createMissedCallLambda({slug:e.slug,roleArn:r,notificationTopicArn:i,callLogTable:s,webhookUrl:e.webhookUrl})),n[`${e.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${e.slug}PhoneNotificationTopic`}},n[`${e.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${e.slug}CallLogTable`}},n[`${e.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${e.slug}VoicemailBucket`}},{resources:t,outputs:n}}}class ce{static createQueue(e){let{slug:t,environment:n,name:r,delaySeconds:i=0,visibilityTimeout:s=30,messageRetentionPeriod:a=345600,maxMessageSize:o=262144,receiveMessageWaitTime:c=0,fifo:l=!1,contentBasedDeduplication:u=!1,encrypted:m=!0,kmsKeyId:p}=e,g=r||S({slug:t,environment:n,resourceType:"queue"}),y=l?`${g}.fifo`:g,h=f(g),b={Type:"AWS::SQS::Queue",Properties:{QueueName:y,DelaySeconds:i,MaximumMessageSize:o,MessageRetentionPeriod:a,ReceiveMessageWaitTimeSeconds:c,VisibilityTimeout:s,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:n}]}};if(l)b.Properties.FifoQueue=!0,b.Properties.ContentBasedDeduplication=u;if(m)if(p)b.Properties.KmsMasterKeyId=p;else b.Properties.SqsManagedSseEnabled=!0;return{queue:b,logicalId:h}}static createDeadLetterQueue(e,t){let{slug:n,environment:r,maxReceiveCount:i=3}=t,s=S({slug:n,environment:r,resourceType:"dlq"}),a=f(s),o={Type:"AWS::SQS::Queue",Properties:{QueueName:s,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r},{Key:"Type",Value:"DeadLetterQueue"}]}},c={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:v.GetAtt(a,"Arn"),maxReceiveCount:i}}};return{deadLetterQueue:o,updatedSourceQueue:c,deadLetterLogicalId:a}}static createSchedule(e,t){let{slug:n,environment:r,name:i,description:s,enabled:a=!0}=t,o=i||S({slug:n,environment:r,resourceType:"schedule"}),c=f(o);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:o,Description:s,ScheduleExpression:e,State:a?"ENABLED":"DISABLED",Targets:[]}},logicalId:c}}static scheduleEcsTask(e,t,n){let{slug:r,environment:i,name:s,description:a,enabled:o=!0,taskDefinitionArn:c,clusterArn:l,subnets:u,securityGroups:m=[],assignPublicIp:p=!1,taskCount:g=1,containerOverrides:y}=n,h=s||S({slug:r,environment:i,resourceType:"ecs-schedule"}),b=f(h),T={Id:"1",Arn:l,RoleArn:t,EcsParameters:{TaskDefinitionArn:c,TaskCount:g,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:u,SecurityGroups:m,AssignPublicIp:p?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(y&&y.length>0)T.Input=JSON.stringify({containerOverrides:y});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:h,Description:a||`Scheduled ECS task: ${c}`,ScheduleExpression:e,State:o?"ENABLED":"DISABLED",Targets:[T]}},logicalId:b}}static scheduleLambda(e,t){let{slug:n,environment:r,name:i,description:s,enabled:a=!0,functionArn:o,input:c}=t,l=i||S({slug:n,environment:r,resourceType:"lambda-schedule"}),u=f(l),m={Id:"1",Arn:o};if(c)m.Input=JSON.stringify(c);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:l,Description:s||`Scheduled Lambda: ${o}`,ScheduleExpression:e,State:a?"ENABLED":"DISABLED",Targets:[m]}},logicalId:u}}static scheduleSqsMessage(e,t){let{slug:n,environment:r,name:i,description:s,enabled:a=!0,queueArn:o,messageGroupId:c}=t,l=i||S({slug:n,environment:r,resourceType:"sqs-schedule"}),u=f(l),m={Id:"1",Arn:o};if(c)m.SqsParameters={MessageGroupId:c};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:l,Description:s||`Scheduled SQS message: ${o}`,ScheduleExpression:e,State:a?"ENABLED":"DISABLED",Targets:[m]}},logicalId:u}}static addTarget(e,t){if(!e.Properties.Targets)e.Properties.Targets=[];let n={Id:t.id,Arn:t.arn};if(t.roleArn)n.RoleArn=t.roleArn;if(t.input)n.Input=JSON.stringify(t.input);return e.Properties.Targets.push(n),e}static toCronExpression(e){if(e.startsWith("cron(")||e.startsWith("rate("))return e;return`cron(${e})`}static rateExpression(e,t){return`rate(${e} ${t})`}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(e){let t=e.toLowerCase().trim(),n=t.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(n){let l=parseInt(n[1],10),u=n[2].toLowerCase(),m=u.endsWith("s")&&l===1?u.slice(0,-1):u,p=!u.endsWith("s")&&l>1?`${u}s`:u;return`rate(${l} ${l===1?m:p})`}let r=t.match(/^every\s+(minute|hour|day)$/i);if(r)return`rate(1 ${r[1]})`;let i={"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(i[t])return i[t];let s=t.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(s){let l=parseInt(s[1],10),u=s[2]?.toLowerCase();if(u==="pm"&&l!==12)l+=12;else if(u==="am"&&l===12)l=0;return`cron(0 ${l} * * ? *)`}let a=t.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(a){let l=parseInt(a[1],10);return`cron(${parseInt(a[2],10)} ${l} * * ? *)`}let o={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},c=t.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(c)return`cron(0 0 ? * ${o[c[1].toLowerCase()]} *)`;return ce.toCronExpression(e)}static JobConfig={create:(e)=>{let{name:t,handler:n,retries:r=3,backoff:i="exponential",backoffDelay:s=1000,maxDelay:a=30000,timeout:o=60000,jitter:c=!0}=e;return{name:t,handler:n,retries:r,backoff:i,backoffDelay:s,maxDelay:a,timeout:o,jitter:c}},calculateDelay:(e,t)=>{let{backoff:n,backoffDelay:r,maxDelay:i,jitter:s}=t,a;switch(n){case"linear":a=r*e;break;case"exponential":a=r*2**(e-1);break;case"fixed":default:a=r}if(a=Math.min(a,i||Number.MAX_SAFE_INTEGER),s){let o=a*0.25*Math.random();a+=o}return Math.floor(a)},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(e){let{containerName:t,jobClass:n,jobData:r,environment:i={}}=e,s=[{name:"JOB_CLASS",value:n}];if(r)s.push({name:"JOB_DATA",value:JSON.stringify(r)});for(let[a,o]of Object.entries(i))s.push({name:a,value:o});return{name:t,command:["bun","run","app/Jobs/runner.ts"],environment:s}}static createScheduledJob(e){let{slug:t,environment:n,schedule:r,jobClass:i,jobData:s,taskDefinitionArn:a,clusterArn:o,subnets:c,securityGroups:l=[],roleArn:u,containerName:m="app"}=e,p=ce.rateStringToExpression(r),g=ce.createJobContainerOverride({containerName:m,jobClass:i,jobData:s});return ce.scheduleEcsTask(p,u,{slug:t,environment:n,name:`${t}-${i.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${i}`,taskDefinitionArn:a,clusterArn:o,subnets:c,securityGroups:l,containerOverrides:[g]})}static QueuePresets={highThroughput:(e,t)=>ce.createQueue({slug:e,environment:t,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,t)=>ce.createQueue({slug:e,environment:t,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,t)=>ce.createQueue({slug:e,environment:t,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,t,n=60)=>ce.createQueue({slug:e,environment:t,delaySeconds:n})}}class Te{static async discoverJobs(e){let{projectRoot:t,jobsPath:n="app/Jobs"}=e,r=`${t}/${n}`,i=[];try{let s=await import("node:fs"),a=await import("node:path");if(!s.existsSync(r))return[];let o=s.readdirSync(r).filter((c)=>c.endsWith(".ts")&&!c.startsWith("_")&&c!=="runner.ts");for(let c of o){let l=a.join(r,c),u=c.replace(".ts",""),m=s.readFileSync(l,"utf-8"),p=Te.parseJobMetadata(m,u,l);if(p)i.push(p)}}catch{return[]}return i}static parseJobMetadata(e,t,n){let r=e.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/schedule:\s*['"`]([^'"`]+)['"`]/),i=e.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||e.match(/enabled:\s*(true|false)/),s=e.match(/export\s+const\s+retries\s*=\s*(\d+)/)||e.match(/retries:\s*(\d+)/),a=e.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||e.match(/timeout:\s*(\d+)/),o=e.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||e.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),c=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;return{name:t,path:n,schedule:r?.[1],handler:`${t}.handle`,enabled:i?.[1]!=="false",retries:s?parseInt(s[1],10):void 0,backoff:o?.[1],timeout:a?parseInt(a[1],10):void 0,description:c?.[1]}}static async discoverActions(e){let{projectRoot:t,actionsPath:n="app/Actions"}=e,r=`${t}/${n}`,i=[];try{let s=await import("node:fs"),a=await import("node:path");if(!s.existsSync(r))return[];let o=s.readdirSync(r).filter((c)=>c.endsWith(".ts")&&!c.startsWith("_"));for(let c of o){let l=a.join(r,c),u=c.replace(".ts",""),m=s.readFileSync(l,"utf-8"),p=Te.parseActionMetadata(m,u,l);if(p)i.push(p)}}catch{return[]}return i}static parseActionMetadata(e,t,n){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let i=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:t,path:n,handler:`${t}.handle`,description:i?.[1]}}static generateScheduledJobResources(e){let{slug:t,environment:n,jobs:r,taskDefinitionArn:i,clusterArn:s,subnets:a,securityGroups:o=[],roleArn:c,containerName:l="app"}=e,u={},m=0;for(let p of r){if(!p.schedule||!p.enabled)continue;let{rule:g,logicalId:y}=ce.createScheduledJob({slug:t,environment:n,schedule:p.schedule,jobClass:p.name,taskDefinitionArn:i,clusterArn:s,subnets:a,securityGroups:o,roleArn:c,containerName:l});u[y]=g,m++}return{rules:u,count:m}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
1639
1639
  /**
1640
1640
  * Job Runner Script
1641
1641
  * This script is invoked by ECS scheduled tasks to run jobs
@@ -1680,7 +1680,7 @@ catch (error) {
1680
1680
  }
1681
1681
 
1682
1682
  run()
1683
- `}static async generateJobManifest(e){let t=await Ce.discoverJobs(e),n=t.filter((r)=>r.schedule&&r.enabled);return{jobs:t,scheduledCount:n.length,totalCount:t.length}}}var _d={loadJobs:Ce.discoverJobs,loadActions:Ce.discoverActions,generateScheduledJobs:Ce.generateScheduledJobResources,generateRunner:Ce.generateJobRunnerScript,paths:{jobs:"app/Jobs",actions:"app/Actions",runner:"app/Jobs/runner.ts"}};var pr=`
1683
+ `}static async generateJobManifest(e){let t=await Te.discoverJobs(e),n=t.filter((r)=>r.schedule&&r.enabled);return{jobs:t,scheduledCount:n.length,totalCount:t.length}}}var _d={loadJobs:Te.discoverJobs,loadActions:Te.discoverActions,generateScheduledJobs:Te.generateScheduledJobResources,generateRunner:Te.generateJobRunnerScript,paths:{jobs:"app/Jobs",actions:"app/Actions",runner:"app/Jobs/runner.ts"}};var pr=`
1684
1684
  const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
1685
1685
  const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
1686
1686
 
@@ -2283,14 +2283,14 @@ function resolveTemplate(template, data) {
2283
2283
  }
2284
2284
  return result;
2285
2285
  }
2286
- `;class J{static LambdaCode={send:Kt,receive:gr,deliveryStatus:pr};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let t={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)t.SenderId=e.senderId;if(e.shortCode)t.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:t}}}static createSmsLambdaRole(e){return{[`${e.slug}SmsLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.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(e){return{[`${e.slug}SmsSendLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-send`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:J.LambdaCode.send},Environment:{Variables:{PINPOINT_APP_ID:e.pinpointAppId,MESSAGE_LOG_TABLE:e.messageLogTable||"",SMS_SENDER_ID:e.senderId||"",SMS_ORIGINATION_NUMBER:e.originationNumber||""}}}}}}static createReceiveLambda(e){return{[`${e.slug}SmsReceiveLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-receive`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:J.LambdaCode.receive},Environment:{Variables:{OPT_OUT_TABLE:e.optOutTable||"",MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createDeliveryStatusLambda(e){return{[`${e.slug}SmsDeliveryStatusLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-delivery-status`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:J.LambdaCode.deliveryStatus},Environment:{Variables:{MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createMessageLogTable(e){return{[`${e.slug}SmsMessageLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-messages`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createOptOutTable(e){return{[`${e.slug}SmsOptOutTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-optouts`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}}static createNotificationTopic(e){return{[`${e.slug}SmsNotificationTopic`]:{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-sms-notifications`}}}}static createCompleteSetup(e){let t={},n={};Object.assign(t,J.createPinpointApp({slug:e.slug})),Object.assign(t,J.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(t,J.createSmsLambdaRole({slug:e.slug})),Object.assign(t,J.createMessageLogTable({slug:e.slug})),Object.assign(t,J.createOptOutTable({slug:e.slug})),Object.assign(t,J.createNotificationTopic({slug:e.slug}));let r={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},i={Ref:`${e.slug}PinpointApp`},s={Ref:`${e.slug}SmsMessageLogTable`},a={Ref:`${e.slug}SmsOptOutTable`},o={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(t,J.createSendLambda({slug:e.slug,roleArn:r,pinpointAppId:i,messageLogTable:s,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(t,J.createReceiveLambda({slug:e.slug,roleArn:r,optOutTable:a,messageLogTable:s,notificationTopicArn:o,webhookUrl:e.webhookUrl}));return Object.assign(t,J.createDeliveryStatusLambda({slug:e.slug,roleArn:r,messageLogTable:s,notificationTopicArn:o,webhookUrl:e.webhookUrl})),n[`${e.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${e.slug}PinpointApp`}},n[`${e.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${e.slug}SmsSendLambda`,"Arn"]}},n[`${e.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${e.slug}SmsNotificationTopic`}},n[`${e.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${e.slug}SmsMessageLogTable`}},{resources:t,outputs:n}}}function qt(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((r)=>r.charAt(0).toUpperCase()+r.slice(1)).join("")||"User"}function Aa(e,t){let n=(e||t).replace(/^\/+|\/+$/g,"");if(!n||n.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${t}`);return n}function Ca(e){let t=e.storage;if(t?.type==="efs"){let r="fileSystemId"in t?t.fileSystemId:void 0;if(!r||typeof r==="string"&&!r.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:r,posixProfile:t.posixProfile}}let n=(t?.type==="s3"?t.bucket??e.bucket:e.bucket)?.trim();if(!n)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:n}}function va(e,t,n){let r=t.posixProfile??n;if(!r)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let i of[r.uid,r.gid,...r.secondaryGids??[]])if(!Number.isInteger(i)||i<0||i>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${i}`);return{Uid:r.uid,Gid:r.gid,...r.secondaryGids?.length?{SecondaryGids:r.secondaryGids}:{}}}function Ta(e,t){return typeof e==="string"?`/${e}/${t}`:{"Fn::Sub":[`/\${FileSystemId}/${t}`,{FileSystemId:e}]}}function Ra(e){return typeof e==="string"?{"Fn::Sub":"arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}".replace("${FileSystemId}",e)}:{"Fn::Sub":["arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}",{FileSystemId:e}]}}class Pa{static create(e){let t=Ca(e),n=t.type==="efs"?"EFS":"S3",r=e.endpointType??"PUBLIC";if(r==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let i=`${qt(e.slug)}${qt(e.environment)}Sftp`,s=`${i}Server`,a={},o;if(e.logging!==!1){let c=`${i}LoggingRole`;a[c]={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/*"}]}}]}},o={"Fn::GetAtt":[c,"Arn"]}}a[s]={Type:"AWS::Transfer::Server",Properties:{Domain:n,EndpointType:r,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...r==="VPC"?{EndpointDetails:{VpcId:e.endpointDetails.vpcId,SubnetIds:e.endpointDetails.subnetIds,...e.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:e.endpointDetails.securityGroupIds}:{},...e.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:e.endpointDetails.addressAllocationIds}:{}}}:{},...e.securityPolicyName?{SecurityPolicyName:e.securityPolicyName}:{},...o?{LoggingRole:o}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[c,l]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(c))throw Error(`sftp: invalid username ${c}`);if(!l.sshPublicKeys.length)throw Error(`sftp: user ${c} requires at least one SSH public key`);let u=qt(c),m=Aa(l.homeDirectory,c),p=`${i}${u}User`,g=l.roleArn;if(!g){let y=`${i}${u}Role`,h;if(t.type==="efs")h=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Ra(t.fileSystemId)}];else{let b=`arn:aws:s3:::${t.bucket}`;h=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:b,Condition:{StringLike:{"s3:prefix":[m,`${m}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${b}/${m}/*`}]}a[y]={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:h}}]}},g={"Fn::GetAtt":[y,"Arn"]}}a[p]={Type:"AWS::Transfer::User",DependsOn:[s],Properties:{ServerId:{Ref:s},UserName:c,Role:g,HomeDirectoryType:"PATH",HomeDirectory:t.type==="efs"?Ta(t.fileSystemId,m):`/${t.bucket}/${m}`,...t.type==="efs"?{PosixProfile:va(c,l,t.posixProfile)}:{},SshPublicKeys:l.sshPublicKeys}}}return{resources:a,serverLogicalId:s,domain:n}}}class ht{static createBedrockRole(e,t){let{slug:n,environment:r,name:i,models:s=["*"],allowStreaming:a=!0}=t,o=i||S({slug:n,environment:r,resourceType:"bedrock-role"}),c=f(o),l=["bedrock:InvokeModel"];if(a)l.push("bedrock:InvokeModelWithResponseStream");let u=s.map((p)=>p==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${p}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:o,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:e},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${o}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:l,Resource:u}]}}],Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r}]}},logicalId:c}}static createBedrockPolicy(e){let{slug:t,environment:n,name:r,models:i=["*"],allowInvoke:s=!0,allowStreaming:a=!0,allowAsync:o=!1}=e,c=r||S({slug:t,environment:n,resourceType:"bedrock-policy"}),l=f(c),u=[];if(s)u.push("bedrock:InvokeModel");if(a)u.push("bedrock:InvokeModelWithResponseStream");if(o)u.push("bedrock:InvokeModelAsync");let m=i.map((g)=>g==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${g}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:u,Resource:m}]}}},logicalId:l}}static enableBedrockForLambda(e){return ht.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return ht.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return ht.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,t=["*"],n=!0){let r=["bedrock:InvokeModel"];if(n)r.push("bedrock:InvokeModelWithResponseStream");let i=t.map((s)=>s==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${s}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:r,Resource:i}]}}),e}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 zt{static createPostgres(e){return zt.createRDSInstance("postgres","16.2",e)}static createMysql(e){return zt.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,t,n){let{slug:r,environment:i,instanceClass:s="db.t3.micro",allocatedStorage:a=20,storageType:o="gp3",masterUsername:c="admin",masterPassword:l,databaseName:u,subnetIds:m,securityGroupIds:p,encrypted:g=!0,kmsKeyId:y,multiAz:h=!1,backupRetentionDays:b=7,publiclyAccessible:v=!1,enableCloudwatchLogs:T=!0,deletionProtection:A=!0}=n,R=S({slug:r,environment:i,resourceType:`${e}-db`}),P=f(R),E,w;if(m&&m.length>0){let D=S({slug:r,environment:i,resourceType:"db-subnet-group"});w=f(D),E={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:D,DBSubnetGroupDescription:`Subnet group for ${R}`,SubnetIds:m,Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:i}]}}}let I={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:R,DBInstanceClass:s,Engine:e,EngineVersion:t,MasterUsername:c,MasterUserPassword:l,AllocatedStorage:a,StorageType:o,StorageEncrypted:g,MultiAZ:h,BackupRetentionPeriod:b,PubliclyAccessible:v,DeletionProtection:A,Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:i}]}};if(u)I.Properties.DBName=u;if(y)I.Properties.KmsKeyId=y;if(w)I.Properties.DBSubnetGroupName=C.Ref(w);if(p&&p.length>0)I.Properties.VPCSecurityGroups=p;if(T)I.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:I,subnetGroup:E,logicalId:P,subnetGroupId:w}}static createReadReplica(e,t){let{slug:n,environment:r,instanceClass:i="db.t3.micro",securityGroupIds:s,publiclyAccessible:a=!1}=t,o=S({slug:n,environment:r,resourceType:"db-replica"}),c=f(o),l={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:o,DBInstanceClass:i,SourceDBInstanceIdentifier:C.Ref(e),PubliclyAccessible:a,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r},{Key:"Type",Value:"ReadReplica"}]}};if(s&&s.length>0)l.Properties.VPCSecurityGroups=s;return{replica:l,logicalId:c}}static createParameterGroup(e,t,n){let{slug:r,environment:i,parameters:s={}}=n,a=S({slug:r,environment:i,resourceType:"db-params"}),o=f(a),c=e==="postgres"?`postgres${t.split(".")[0]}`:`mysql${t.split(".")[0]}.${t.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:a,Description:`Parameter group for ${a}`,Family:c,Parameters:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i}]}},logicalId:o}}static enableBackup(e,t=7){return e.Properties.BackupRetentionPeriod=t,e}static createTable(e){let{slug:t,environment:n,tableName:r,partitionKey:i,sortKey:s,billingMode:a="PAY_PER_REQUEST",readCapacity:o=5,writeCapacity:c=5,streamEnabled:l=!1,streamViewType:u="NEW_AND_OLD_IMAGES",encrypted:m=!0,kmsKeyId:p,pointInTimeRecovery:g=!0,ttlAttribute:y}=e,h=r||S({slug:t,environment:n,resourceType:"table"}),b=f(h),v=[{AttributeName:i.name,AttributeType:i.type}];if(s)v.push({AttributeName:s.name,AttributeType:s.type});let T=[{AttributeName:i.name,KeyType:"HASH"}];if(s)T.push({AttributeName:s.name,KeyType:"RANGE"});let A={Type:"AWS::DynamoDB::Table",Properties:{TableName:h,BillingMode:a,AttributeDefinitions:v,KeySchema:T,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:n}]}};if(a==="PROVISIONED")A.Properties.ProvisionedThroughput={ReadCapacityUnits:o,WriteCapacityUnits:c};if(l)A.Properties.StreamSpecification={StreamViewType:u};if(m)A.Properties.SSESpecification={SSEEnabled:!0,SSEType:p?"KMS":"AES256",KMSMasterKeyId:p};if(g)A.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(y)A.Properties.TimeToLiveSpecification={AttributeName:y,Enabled:!0};return{table:A,logicalId:b}}static addGlobalSecondaryIndex(e,t){let{indexName:n,partitionKey:r,sortKey:i,projectionType:s="ALL",nonKeyAttributes:a,readCapacity:o=5,writeCapacity:c=5}=t;if(!e.Properties.AttributeDefinitions.some((m)=>m.AttributeName===r.name))e.Properties.AttributeDefinitions.push({AttributeName:r.name,AttributeType:r.type});if(i&&!e.Properties.AttributeDefinitions.some((m)=>m.AttributeName===i.name))e.Properties.AttributeDefinitions.push({AttributeName:i.name,AttributeType:i.type});let l=[{AttributeName:r.name,KeyType:"HASH"}];if(i)l.push({AttributeName:i.name,KeyType:"RANGE"});let u={IndexName:n,KeySchema:l,Projection:{ProjectionType:s,NonKeyAttributes:s==="INCLUDE"?a:void 0},ProvisionedThroughput:void 0};if(e.Properties.BillingMode==="PROVISIONED")u.ProvisionedThroughput={ReadCapacityUnits:o,WriteCapacityUnits:c};if(!e.Properties.GlobalSecondaryIndexes)e.Properties.GlobalSecondaryIndexes=[];return e.Properties.GlobalSecondaryIndexes.push(u),e}static enableStreams(e,t="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:t},e}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 Ea{static createRedis(e){let{slug:t,environment:n,nodeType:r="cache.t3.micro",engineVersion:i="7.1",port:s=6379,subnetIds:a,securityGroupIds:o,numCacheClusters:c=2,automaticFailover:l=!0,multiAz:u=!0,clusterMode:m=!1,numNodeGroups:p=1,replicasPerNodeGroup:g=1,atRestEncryption:y=!0,transitEncryption:h=!0,authToken:b,kmsKeyId:v,snapshotRetentionDays:T=7,snapshotWindow:A,maintenanceWindow:R}=e,P=S({slug:t,environment:n,resourceType:"redis"}),E=f(P),w,I;if(a&&a.length>0){let k=S({slug:t,environment:n,resourceType:"cache-subnet-group"});I=f(k),w={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:k,Description:`Subnet group for ${P}`,SubnetIds:a,Tags:[{Key:"Name",Value:k},{Key:"Environment",Value:n}]}}}let D={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:P,ReplicationGroupDescription:`Redis cluster for ${t} ${n}`,Engine:"redis",EngineVersion:i,CacheNodeType:r,Port:s,AutomaticFailoverEnabled:l,MultiAZEnabled:u,AtRestEncryptionEnabled:y,TransitEncryptionEnabled:h,SnapshotRetentionLimit:T,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:n}]}};if(m)D.Properties.NumNodeGroups=p,D.Properties.ReplicasPerNodeGroup=g;else D.Properties.NumCacheClusters=c;if(b)D.Properties.AuthToken=b;if(v)D.Properties.KmsKeyId=v;if(I)D.Properties.CacheSubnetGroupName=C.Ref(I);if(o&&o.length>0)D.Properties.SecurityGroupIds=o;if(A)D.Properties.SnapshotWindow=A;if(R)D.Properties.PreferredMaintenanceWindow=R;return{replicationGroup:D,subnetGroup:w,logicalId:E,subnetGroupId:I}}static createMemcached(e){let{slug:t,environment:n,nodeType:r="cache.t3.micro",engineVersion:i="1.6.22",port:s=11211,numCacheNodes:a=2,subnetIds:o,securityGroupIds:c,azMode:l="cross-az",preferredAzs:u,maintenanceWindow:m}=e,p=S({slug:t,environment:n,resourceType:"memcached"}),g=f(p),y,h;if(o&&o.length>0){let v=S({slug:t,environment:n,resourceType:"cache-subnet-group"});h=f(v),y={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:v,Description:`Subnet group for ${p}`,SubnetIds:o,Tags:[{Key:"Name",Value:v},{Key:"Environment",Value:n}]}}}let b={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:p,CacheNodeType:r,Engine:"memcached",EngineVersion:i,NumCacheNodes:a,Port:s,AZMode:l,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:n}]}};if(h)b.Properties.CacheSubnetGroupName=C.Ref(h);if(c&&c.length>0)b.Properties.VpcSecurityGroupIds=c;if(u&&u.length>0)b.Properties.PreferredAvailabilityZones=u;if(m)b.Properties.PreferredMaintenanceWindow=m;return{cluster:b,subnetGroup:y,logicalId:g,subnetGroupId:h}}static enableClusterMode(e,t=3,n=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=t,e.Properties.ReplicasPerNodeGroup=n,e}static createRedisParameterGroup(e,t){let{slug:n,environment:r,parameters:i={}}=t,s=S({slug:n,environment:r,resourceType:"redis-params"}),a=f(s);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${s}`,Properties:i,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},logicalId:a}}static createMemcachedParameterGroup(e,t){let{slug:n,environment:r,parameters:i={}}=t,s=S({slug:n,environment:r,resourceType:"memcached-params"}),a=f(s);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${s}`,Properties:i,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},logicalId:a}}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 ce{static createUser(e){let{slug:t,environment:n,userName:r,groups:i,managedPolicyArns:s}=e,a=r||S({slug:t,environment:n,resourceType:"user"}),o=f(a),c={Type:"AWS::IAM::User",Properties:{UserName:a,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:n}]}};if(i&&i.length>0)c.Properties.Groups=i;if(s&&s.length>0)c.Properties.ManagedPolicyArns=s;return{user:c,logicalId:o}}static createRole(e){let{slug:t,environment:n,roleName:r,servicePrincipal:i,awsPrincipal:s,managedPolicyArns:a}=e,o=r||S({slug:t,environment:n,resourceType:"role"}),c=f(o),l={};if(i)l.Service=i;if(s)l.AWS=s;let u={Type:"AWS::IAM::Role",Properties:{RoleName:o,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:l,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}};if(a&&a.length>0)u.Properties.ManagedPolicyArns=a;return{role:u,logicalId:c}}static createGroup(e){let{slug:t,environment:n,groupName:r,managedPolicyArns:i}=e,s=r||S({slug:t,environment:n,resourceType:"group"}),a=f(s),o={Type:"AWS::IAM::Group",Properties:{GroupName:s}};if(i&&i.length>0)o.Properties.ManagedPolicyArns=i;return{group:o,logicalId:a}}static createPolicy(e){let{slug:t,environment:n,policyName:r,description:i,statements:s}=e,a=r||S({slug:t,environment:n,resourceType:"policy"}),o=f(a),c=s.map((u)=>({Sid:u.sid,Effect:u.effect||"Allow",Action:u.actions,Resource:u.resources,Condition:u.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:a,Description:i||`Managed policy for ${a}`,PolicyDocument:{Version:"2012-10-17",Statement:c}}},logicalId:o}}static attachPolicyToRole(e,t){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(t))e.Properties.ManagedPolicyArns.push(t);return e}static attachPolicyToUser(e,t){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(t))e.Properties.ManagedPolicyArns.push(t);return e}static attachPolicyToGroup(e,t){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(t))e.Properties.ManagedPolicyArns.push(t);return e}static addInlinePolicyToRole(e,t,n){if(!e.Properties.Policies)e.Properties.Policies=[];let r=n.map((i)=>({Effect:i.effect||"Allow",Action:i.actions,Resource:i.resources}));return e.Properties.Policies.push({PolicyName:t,PolicyDocument:{Version:"2012-10-17",Statement:r}}),e}static addInlinePolicyToUser(e,t,n){if(!e.Properties.Policies)e.Properties.Policies=[];let r=n.map((i)=>({Effect:i.effect||"Allow",Action:i.actions,Resource:i.resources}));return e.Properties.Policies.push({PolicyName:t,PolicyDocument:{Version:"2012-10-17",Statement:r}}),e}static createAccessKey(e,t){let{slug:n,environment:r,status:i="Active"}=t,s=S({slug:n,environment:r,resourceType:"access-key"}),a=f(s);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:C.Ref(e),Status:i}},logicalId:a}}static createInstanceProfile(e,t){let{slug:n,environment:r,profileName:i}=t,s=i||S({slug:n,environment:r,resourceType:"instance-profile"}),a=f(s);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:s,Roles:[C.Ref(e)]}},logicalId:a}}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(e){let{slug:t,environment:n,permissions:r,createAccessKey:i=!0}=e,s={},a=[];if(r.s3Buckets&&r.s3Buckets.length>0)a.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...r.s3Buckets,...r.s3Buckets.map((g)=>`${g}/*`)]});if(r.cloudFrontDistributions&&r.cloudFrontDistributions.length>0)a.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:r.cloudFrontDistributions});if(r.ecrRepositories&&r.ecrRepositories.length>0)a.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:r.ecrRepositories}),a.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(r.ecsServices&&r.ecsServices.length>0)a.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:r.ecsServices}),a.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),a.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(r.cloudFormationStacks&&r.cloudFormationStacks.length>0)a.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:r.cloudFormationStacks});if(r.lambdaFunctions&&r.lambdaFunctions.length>0)a.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:r.lambdaFunctions});if(r.secretsManagerSecrets&&r.secretsManagerSecrets.length>0)a.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:r.secretsManagerSecrets});let{policy:o,logicalId:c}=ce.createPolicy({slug:t,environment:n,policyName:S({slug:t,environment:n,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${t} (${n})`,statements:a});s[c]=o;let{user:l,logicalId:u}=ce.createUser({slug:t,environment:n,userName:S({slug:t,environment:n,resourceType:"cicd-user"}),managedPolicyArns:[C.Ref(c)]});s[u]=l;let m,p;if(i){let g=ce.createAccessKey(u,{slug:t,environment:n});m=g.accessKey,p=g.logicalId,s[p]=m}return{user:l,accessKey:m,policy:o,userLogicalId:u,accessKeyLogicalId:p,policyLogicalId:c,resources:s}}static createCrossAccountRole(e){let{slug:t,environment:n,trustedAccountIds:r,externalId:i,permissions:s,maxSessionDuration:a=3600}=e,o={},{policy:c,logicalId:l}=ce.createPolicy({slug:t,environment:n,policyName:S({slug:t,environment:n,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${t} (${n})`,statements:s});o[l]=c;let u=S({slug:t,environment:n,resourceType:"cross-account-role"}),m=f(u),p={};if(i)p.StringEquals={"sts:ExternalId":i};let g={Type:"AWS::IAM::Role",Properties:{RoleName:u,MaxSessionDuration:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:r.map((y)=>`arn:aws:iam::${y}:root`)},Action:"sts:AssumeRole",...Object.keys(p).length>0?{Condition:p}:{}}]},ManagedPolicyArns:[C.Ref(l)],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n},{Key:"Purpose",Value:"Cross-Account Access"}]}};return o[m]=g,{role:g,policy:c,roleLogicalId:m,policyLogicalId:l,resources:o}}static createCliUser(e){let{slug:t,environment:n,permissions:r="readonly"}=e,i={},s=[],a=[];switch(r){case"readonly":a=[ce.ManagedPolicies.ReadOnlyAccess];break;case"deploy":s=[{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":a=[ce.ManagedPolicies.AdministratorAccess];break}let o,c;if(s.length>0){let g=ce.createPolicy({slug:t,environment:n,policyName:S({slug:t,environment:n,resourceType:"cli-policy"}),description:`CLI access policy for ${t} (${n})`,statements:s});o=g.policy,c=g.logicalId,i[c]=o,a=[C.Ref(c)]}let{user:l,logicalId:u}=ce.createUser({slug:t,environment:n,userName:S({slug:t,environment:n,resourceType:"cli-user"}),managedPolicyArns:a});i[u]=l;let{accessKey:m,logicalId:p}=ce.createAccessKey(u,{slug:t,environment:n});return i[p]=m,{user:l,accessKey:m,policy:o,userLogicalId:u,accessKeyLogicalId:p,policyLogicalId:c,resources:i}}static CiCdPolicies={s3Deployment:(e)=>[{sid:"S3ListBuckets",actions:["s3:ListBucket","s3:GetBucketLocation"],resources:e},{sid:"S3Objects",actions:["s3:GetObject","s3:PutObject","s3:DeleteObject"],resources:e.map((t)=>`${t}/*`)}],cloudFrontInvalidation:(e)=>[{sid:"CloudFrontInvalidation",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations"],resources:e}],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:(e)=>[{sid:"ECRAuth",actions:["ecr:GetAuthorizationToken"],resources:"*"},{sid:"ECRPush",actions:["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:e}],lambdaDeployment:(e)=>[{sid:"LambdaDeploy",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion"],resources:e}],cloudFormationDeployment:(e)=>[{sid:"CloudFormationDeploy",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate"],resources:e}]}}class wa{static createRestApi(e){let{slug:t,environment:n,name:r,description:i,endpointType:s="REGIONAL",binaryMediaTypes:a,compressionSize:o}=e,c=r||S({slug:t,environment:n,resourceType:"rest-api"}),l=f(c),u={Type:"AWS::ApiGateway::RestApi",Properties:{Name:c,Description:i||`REST API for ${t} ${n}`,EndpointConfiguration:{Types:[s]},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:n}]}};if(a&&a.length>0)u.Properties.BinaryMediaTypes=a;if(o!==void 0)u.Properties.MinimumCompressionSize=o;return{restApi:u,logicalId:l}}static createHttpApi(e){let{slug:t,environment:n,name:r,description:i,corsEnabled:s=!0,corsOrigins:a=["*"],corsMethods:o=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:c=["*"],corsMaxAge:l=86400,corsAllowCredentials:u=!1}=e,m=r||S({slug:t,environment:n,resourceType:"http-api"}),p=f(m),g={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:m,Description:i||`HTTP API for ${t} ${n}`,ProtocolType:"HTTP",Tags:{Name:m,Environment:n}}};if(s)g.Properties.CorsConfiguration={AllowOrigins:a,AllowMethods:o,AllowHeaders:c,MaxAge:l,AllowCredentials:u};return{httpApi:g,logicalId:p}}static createWebSocketApi(e){let{slug:t,environment:n,name:r,description:i}=e,s=r||S({slug:t,environment:n,resourceType:"ws-api"}),a=f(s);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:s,Description:i||`WebSocket API for ${t} ${n}`,ProtocolType:"WEBSOCKET",Tags:{Name:s,Environment:n}}},logicalId:a}}static createDeployment(e,t){let{slug:n,environment:r,description:i}=t,s=S({slug:n,environment:r,resourceType:"api-deployment"}),a=f(s);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:C.Ref(e),Description:i||`Deployment for ${s}`}},logicalId:a}}static createStage(e,t,n){let{slug:r,environment:i,stageName:s,description:a,cacheEnabled:o=!1,cacheSize:c="0.5",variables:l,throttling:u}=n,m=S({slug:r,environment:i,resourceType:"api-stage"}),p=f(m),g={Type:"AWS::ApiGateway::Stage",Properties:{StageName:s||i,RestApiId:C.Ref(e),DeploymentId:C.Ref(t),Description:a,CacheClusterEnabled:o,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:i}]}};if(o)g.Properties.CacheClusterSize=c;if(l)g.Properties.Variables=l;if(u)g.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:u.burstLimit,ThrottlingRateLimit:u.rateLimit}];return{stage:g,logicalId:p}}static createAuthorizer(e,t){let{slug:n,environment:r,name:i,type:s,functionArn:a,identitySource:o,userPoolArns:c,ttl:l=300}=t,u=i||S({slug:n,environment:r,resourceType:"api-authorizer"}),m=f(u),p={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:u,Type:s,RestApiId:C.Ref(e),AuthorizerResultTtlInSeconds:l}};if(s==="TOKEN"||s==="REQUEST"){if(!a)throw Error("Lambda authorizer requires functionArn");p.Properties.AuthorizerUri=a,p.Properties.IdentitySource=o||"method.request.header.Authorization"}if(s==="COGNITO_USER_POOLS"){if(!c||c.length===0)throw Error("Cognito authorizer requires userPoolArns");p.Properties.ProviderARNs=c,p.Properties.IdentitySource=o||"method.request.header.Authorization"}return{authorizer:p,logicalId:m}}static setCors(e,t={}){let{origins:n=["*"],methods:r=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:i=["*"],maxAge:s=86400,allowCredentials:a=!1}=t;return e.Properties.CorsConfiguration={AllowOrigins:n,AllowMethods:r,AllowHeaders:i,MaxAge:s,AllowCredentials:a},e}static addThrottling(e,t=5000,n=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:t,ThrottlingRateLimit:n}),e}static enableCaching(e,t="0.5",n=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=t,!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:n}),e}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(e){let{slug:t,environment:n,topicName:r,displayName:i,encrypted:s=!1,kmsKeyId:a}=e,o=r||S({slug:t,environment:n,resourceType:"topic"}),c=f(o),l={Type:"AWS::SNS::Topic",Properties:{TopicName:o,DisplayName:i||o,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}};if(s&&a)l.Properties.KmsMasterKeyId=a;return{topic:l,logicalId:c}}static subscribe(e,t){let{slug:n,environment:r,protocol:i,endpoint:s,filterPolicy:a,rawMessageDelivery:o=!1}=t,c=S({slug:n,environment:r,resourceType:"subscription"}),l=s.replace(/[^a-zA-Z0-9]/g,""),u=l.length>12?l.slice(-12):l,m=f(`${c}-${i}-${u}`),p={Type:"AWS::SNS::Subscription",Properties:{TopicArn:C.Ref(e),Protocol:i,Endpoint:s,RawMessageDelivery:o}};if(a)p.Properties.FilterPolicy=a;return{subscription:p,logicalId:m}}static subscribeEmail(e,t,n){return te.subscribe(e,{...n,protocol:"email",endpoint:t})}static subscribeLambda(e,t,n){return te.subscribe(e,{...n,protocol:"lambda",endpoint:t,rawMessageDelivery:!0})}static subscribeSqs(e,t,n){return te.subscribe(e,{...n,protocol:"sqs",endpoint:t})}static subscribeHttp(e,t,n){let r=t.startsWith("https://")?"https":"http";return te.subscribe(e,{...n,protocol:r,endpoint:t})}static subscribeSms(e,t,n){return te.subscribe(e,{...n,protocol:"sms",endpoint:t})}static setTopicPolicy(e,t){let{slug:n,environment:r,allowedPrincipals:i,allowedServices:s,actions:a="SNS:Publish"}=t,o=S({slug:n,environment:r,resourceType:"topic-policy"}),c=f(o),l={};if(i)l.AWS=i;if(s)l.Service=s;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[C.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:l,Action:a,Resource:C.Ref(e)}]}}},logicalId:c}}static allowCloudWatchAlarms(e,t){return te.setTopicPolicy(e,{...t,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,t){return te.setTopicPolicy(e,{...t,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,t){return te.setTopicPolicy(e,{...t,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,t){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=t,e}static addInlineSubscription(e,t,n){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:t,Endpoint:n}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,t,n)=>({[e]:[{numeric:[">=",t,"<=",n]}]}),prefix:(e,t)=>({[e]:[{prefix:t}]}),and:(...e)=>Object.assign({},...e),exists:(e,t)=>({[e]:[{exists:t}]})};static UseCases={createAlertTopic:(e)=>te.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>te.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>te.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class Ia{static createStateMachine(e){let{slug:t,environment:n,stateMachineName:r,type:i="STANDARD",definition:s,roleArn:a,loggingConfiguration:o,tracingConfiguration:c}=e,l=r||S({slug:t,environment:n,resourceType:"state-machine"}),u=f(l),m,p,g;if(a)g=a;else{let h=S({slug:t,environment:n,resourceType:"state-machine-role"});p=f(h),m={Type:"AWS::IAM::Role",Properties:{RoleName:h,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:h},{Key:"Environment",Value:n}]}},g=C.GetAtt(p,"Arn")}let y={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:l,StateMachineType:i,DefinitionString:JSON.stringify(s),RoleArn:g,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:n}]}};if(o)y.Properties.LoggingConfiguration={Level:o.level,IncludeExecutionData:o.includeExecutionData,Destinations:o.destinations?.map((h)=>({CloudWatchLogsLogGroup:{LogGroupArn:h}}))};if(c)y.Properties.TracingConfiguration={Enabled:c.enabled};return{stateMachine:y,logicalId:u,role:m,roleLogicalId:p}}static createLambdaTask(e,t){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:t?.parameters||{"Input.$":"$"}},ResultPath:t?.resultPath,Retry:t?.retry,Catch:t?.catch,Next:t?.next,End:t?.end}}static createDynamoDBTask(e,t,n,r){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"}[e],Parameters:{TableName:t,...n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSNSPublishTask(e,t,n){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:t},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createSQSSendMessageTask(e,t,n){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:t},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createPassState(e){return{Type:"Pass",Result:e?.result,ResultPath:e?.resultPath,Parameters:e?.parameters,Next:e?.next,End:e?.end}}static createWaitState(e){return{Type:"Wait",Seconds:e.seconds,Timestamp:e.timestamp,SecondsPath:e.secondsPath,TimestampPath:e.timestampPath,Next:e.next,End:e.end}}static createChoiceState(e,t){return{Type:"Choice",Choices:e,Default:t}}static createParallelState(e,t){return{Type:"Parallel",Branches:e,ResultPath:t?.resultPath,Retry:t?.retry,Catch:t?.catch,Next:t?.next,End:t?.end}}static createMapState(e,t){return{Type:"Map",ItemsPath:t?.itemsPath||"$.items",Iterator:e,MaxConcurrency:t?.maxConcurrency,ResultPath:t?.resultPath,Retry:t?.retry,Catch:t?.catch,Next:t?.next,End:t?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,t){return{Type:"Fail",Error:e,Cause:t}}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:(e,t,n,r)=>({ErrorEquals:e,IntervalSeconds:t,MaxAttempts:n,BackoffRate:r})};static CatchPolicies={all:(e,t)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:t||"$.error"}),specific:(e,t,n)=>({ErrorEquals:e,Next:t,ResultPath:n||"$.error"})};static Patterns={sequential:(e,t,n)=>{let r={};return n.forEach((i,s)=>{let a=s===n.length-1;r[i.name]={...i.state,Next:a?void 0:n[s+1].name,End:a}}),{Comment:"Sequential workflow",StartAt:n[0].name,States:r}},fanout:(e,t,n)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:n.map((r)=>r.definition),End:!0}}}),map:(e,t,n,r)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:n,MaxConcurrency:r,End:!0}}}),withErrorHandling:(e,t,n,r)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...n,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:r,Success:{Type:"Succeed"}}})}}class fr{static createAlarm(e){let{slug:t,environment:n,alarmName:r,metricName:i,namespace:s,statistic:a="Average",period:o=300,evaluationPeriods:c=1,threshold:l,comparisonOperator:u,treatMissingData:m="notBreaching",actionsEnabled:p=!0,alarmActions:g,okActions:y,insufficientDataActions:h,dimensions:b,unit:v,datapointsToAlarm:T}=e,A=r||S({slug:t,environment:n,resourceType:"alarm"}),R=f(A),P={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:A,MetricName:i,Namespace:s,Statistic:a,Period:o,EvaluationPeriods:c,Threshold:l,ComparisonOperator:u,TreatMissingData:m,ActionsEnabled:p}};if(g&&g.length>0)P.Properties.AlarmActions=g;if(y&&y.length>0)P.Properties.OKActions=y;if(h&&h.length>0)P.Properties.InsufficientDataActions=h;if(b)P.Properties.Dimensions=Object.entries(b).map(([E,w])=>({Name:E,Value:w}));if(v)P.Properties.Unit=v;if(T!==void 0)P.Properties.DatapointsToAlarm=T;return{alarm:P,logicalId:R}}static createCompositeAlarm(e){let{slug:t,environment:n,alarmName:r,alarmRule:i,actionsEnabled:s=!0,alarmActions:a,okActions:o,insufficientDataActions:c}=e,l=r||S({slug:t,environment:n,resourceType:"composite-alarm"}),u=f(l),m={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:l,AlarmRule:i,ActionsEnabled:s}};if(a&&a.length>0)m.Properties.AlarmActions=a;if(o&&o.length>0)m.Properties.OKActions=o;if(c&&c.length>0)m.Properties.InsufficientDataActions=c;return{alarm:m,logicalId:u}}static createDashboard(e){let{slug:t,environment:n,dashboardName:r,widgets:i}=e,s=r||S({slug:t,environment:n,resourceType:"dashboard"}),a=f(s),o={widgets:i.map((l)=>({type:l.type,x:l.x,y:l.y,width:l.width,height:l.height,properties:l.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:s,DashboardBody:JSON.stringify(o)}},logicalId:a}}static createLogGroup(e){let{slug:t,environment:n,logGroupName:r,retentionInDays:i,kmsKeyId:s}=e,a=r||S({slug:t,environment:n,resourceType:"log-group"}),o=f(a),c={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:a}};if(i!==void 0)c.Properties.RetentionInDays=i;if(s)c.Properties.KmsKeyId=s;return{logGroup:c,logicalId:o}}static createLogStream(e,t){let{slug:n,environment:r,logStreamName:i}=t,s=i||S({slug:n,environment:r,resourceType:"log-stream"}),a=f(s);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:C.Ref(e),LogStreamName:s}},logicalId:a}}static createMetricFilter(e,t){let{slug:n,environment:r,filterName:i,filterPattern:s,metricTransformations:a}=t,o=i||S({slug:n,environment:r,resourceType:"metric-filter"}),c=f(o);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:C.Ref(e),FilterPattern:s,MetricTransformations:a.map((u)=>({MetricName:u.metricName,MetricNamespace:u.metricNamespace,MetricValue:u.metricValue,DefaultValue:u.defaultValue,Unit:u.unit}))}},logicalId:c}}static AlarmTypes={highCpu:(e,t,n,r=80,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:n},alarmActions:i?[i]:void 0}),highMemory:(e,t,n,r=80,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:n},alarmActions:i?[i]:void 0}),highDisk:(e,t,n,r=80,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:n,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:i?[i]:void 0}),lambdaErrors:(e,t,n,r=5,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:n},alarmActions:i?[i]:void 0}),lambdaThrottles:(e,t,n,r=10,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:n},alarmActions:i?[i]:void 0}),apiGateway5xxErrors:(e,t,n,r=10,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:n},alarmActions:i?[i]:void 0}),apiGateway4xxErrors:(e,t,n,r=50,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:n},alarmActions:i?[i]:void 0}),dynamoDBThrottles:(e,t,n,r=5,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:n},alarmActions:i?[i]:void 0}),rdsCpu:(e,t,n,r=80,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:n},alarmActions:i?[i]:void 0}),rdsFreeStorage:(e,t,n,r=5368709120,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:n},alarmActions:i?[i]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,t,n,r=100,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:n},alarmActions:i?[i]:void 0}),albUnhealthyTargets:(e,t,n,r,i=1,s)=>({slug:e,environment:t,alarmName:`${e}-${t}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:n,TargetGroup:r},alarmActions:s?[s]:void 0}),sesBounceRate:(e,t,n=5,r)=>({slug:e,environment:t,alarmName:`${e}-${t}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:n/100,comparisonOperator:"GreaterThanThreshold",alarmActions:r?[r]:void 0}),sesComplaintRate:(e,t,n=0.1,r)=>({slug:e,environment:t,alarmName:`${e}-${t}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:n/100,comparisonOperator:"GreaterThanThreshold",alarmActions:r?[r]:void 0}),smsDeliveryFailure:(e,t,n,r=10,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:n},alarmActions:i?[i]:void 0}),smsSpendLimit:(e,t,n=100,r)=>({slug:e,environment:t,alarmName:`${e}-${t}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",alarmActions:r?[r]:void 0}),connectMissedCalls:(e,t,n,r=5,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:n},alarmActions:i?[i]:void 0})};static DashboardWidgets={metric:(e,t,n,r,i,s)=>({type:"metric",x:e,y:t,width:n,height:r,properties:{metrics:i,title:s||"Metrics",region:"us-east-1",period:300}}),text:(e,t,n,r,i)=>({type:"text",x:e,y:t,width:n,height:r,properties:{markdown:i}}),log:(e,t,n,r,i,s)=>({type:"log",x:e,y:t,width:n,height:r,properties:{query:`SOURCE '${i.join("' | SOURCE '")}'
2286
+ `;class Y{static LambdaCode={send:Kt,receive:gr,deliveryStatus:pr};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let t={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)t.SenderId=e.senderId;if(e.shortCode)t.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:t}}}static createSmsLambdaRole(e){return{[`${e.slug}SmsLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.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(e){return{[`${e.slug}SmsSendLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-send`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Y.LambdaCode.send},Environment:{Variables:{PINPOINT_APP_ID:e.pinpointAppId,MESSAGE_LOG_TABLE:e.messageLogTable||"",SMS_SENDER_ID:e.senderId||"",SMS_ORIGINATION_NUMBER:e.originationNumber||""}}}}}}static createReceiveLambda(e){return{[`${e.slug}SmsReceiveLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-receive`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Y.LambdaCode.receive},Environment:{Variables:{OPT_OUT_TABLE:e.optOutTable||"",MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createDeliveryStatusLambda(e){return{[`${e.slug}SmsDeliveryStatusLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-delivery-status`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Y.LambdaCode.deliveryStatus},Environment:{Variables:{MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createMessageLogTable(e){return{[`${e.slug}SmsMessageLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-messages`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createOptOutTable(e){return{[`${e.slug}SmsOptOutTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-optouts`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}}static createNotificationTopic(e){return{[`${e.slug}SmsNotificationTopic`]:{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-sms-notifications`}}}}static createCompleteSetup(e){let t={},n={};Object.assign(t,Y.createPinpointApp({slug:e.slug})),Object.assign(t,Y.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(t,Y.createSmsLambdaRole({slug:e.slug})),Object.assign(t,Y.createMessageLogTable({slug:e.slug})),Object.assign(t,Y.createOptOutTable({slug:e.slug})),Object.assign(t,Y.createNotificationTopic({slug:e.slug}));let r={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},i={Ref:`${e.slug}PinpointApp`},s={Ref:`${e.slug}SmsMessageLogTable`},a={Ref:`${e.slug}SmsOptOutTable`},o={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(t,Y.createSendLambda({slug:e.slug,roleArn:r,pinpointAppId:i,messageLogTable:s,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(t,Y.createReceiveLambda({slug:e.slug,roleArn:r,optOutTable:a,messageLogTable:s,notificationTopicArn:o,webhookUrl:e.webhookUrl}));return Object.assign(t,Y.createDeliveryStatusLambda({slug:e.slug,roleArn:r,messageLogTable:s,notificationTopicArn:o,webhookUrl:e.webhookUrl})),n[`${e.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${e.slug}PinpointApp`}},n[`${e.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${e.slug}SmsSendLambda`,"Arn"]}},n[`${e.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${e.slug}SmsNotificationTopic`}},n[`${e.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${e.slug}SmsMessageLogTable`}},{resources:t,outputs:n}}}function qt(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((r)=>r.charAt(0).toUpperCase()+r.slice(1)).join("")||"User"}function Aa(e,t){let n=(e||t).replace(/^\/+|\/+$/g,"");if(!n||n.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${t}`);return n}function Ca(e){let t=e.storage;if(t?.type==="efs"){let r="fileSystemId"in t?t.fileSystemId:void 0;if(!r||typeof r==="string"&&!r.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:r,posixProfile:t.posixProfile}}let n=(t?.type==="s3"?t.bucket??e.bucket:e.bucket)?.trim();if(!n)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:n}}function va(e,t,n){let r=t.posixProfile??n;if(!r)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let i of[r.uid,r.gid,...r.secondaryGids??[]])if(!Number.isInteger(i)||i<0||i>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${i}`);return{Uid:r.uid,Gid:r.gid,...r.secondaryGids?.length?{SecondaryGids:r.secondaryGids}:{}}}function Ta(e,t){return typeof e==="string"?`/${e}/${t}`:{"Fn::Sub":[`/\${FileSystemId}/${t}`,{FileSystemId:e}]}}function Ra(e){return typeof e==="string"?{"Fn::Sub":"arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}".replace("${FileSystemId}",e)}:{"Fn::Sub":["arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}",{FileSystemId:e}]}}class Pa{static create(e){let t=Ca(e),n=t.type==="efs"?"EFS":"S3",r=e.endpointType??"PUBLIC";if(r==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let i=`${qt(e.slug)}${qt(e.environment)}Sftp`,s=`${i}Server`,a={},o;if(e.logging!==!1){let c=`${i}LoggingRole`;a[c]={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/*"}]}}]}},o={"Fn::GetAtt":[c,"Arn"]}}a[s]={Type:"AWS::Transfer::Server",Properties:{Domain:n,EndpointType:r,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...r==="VPC"?{EndpointDetails:{VpcId:e.endpointDetails.vpcId,SubnetIds:e.endpointDetails.subnetIds,...e.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:e.endpointDetails.securityGroupIds}:{},...e.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:e.endpointDetails.addressAllocationIds}:{}}}:{},...e.securityPolicyName?{SecurityPolicyName:e.securityPolicyName}:{},...o?{LoggingRole:o}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[c,l]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(c))throw Error(`sftp: invalid username ${c}`);if(!l.sshPublicKeys.length)throw Error(`sftp: user ${c} requires at least one SSH public key`);let u=qt(c),m=Aa(l.homeDirectory,c),p=`${i}${u}User`,g=l.roleArn;if(!g){let y=`${i}${u}Role`,h;if(t.type==="efs")h=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Ra(t.fileSystemId)}];else{let b=`arn:aws:s3:::${t.bucket}`;h=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:b,Condition:{StringLike:{"s3:prefix":[m,`${m}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${b}/${m}/*`}]}a[y]={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:h}}]}},g={"Fn::GetAtt":[y,"Arn"]}}a[p]={Type:"AWS::Transfer::User",DependsOn:[s],Properties:{ServerId:{Ref:s},UserName:c,Role:g,HomeDirectoryType:"PATH",HomeDirectory:t.type==="efs"?Ta(t.fileSystemId,m):`/${t.bucket}/${m}`,...t.type==="efs"?{PosixProfile:va(c,l,t.posixProfile)}:{},SshPublicKeys:l.sshPublicKeys}}}return{resources:a,serverLogicalId:s,domain:n}}}class bt{static createBedrockRole(e,t){let{slug:n,environment:r,name:i,models:s=["*"],allowStreaming:a=!0}=t,o=i||S({slug:n,environment:r,resourceType:"bedrock-role"}),c=f(o),l=["bedrock:InvokeModel"];if(a)l.push("bedrock:InvokeModelWithResponseStream");let u=s.map((p)=>p==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${p}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:o,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:e},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${o}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:l,Resource:u}]}}],Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r}]}},logicalId:c}}static createBedrockPolicy(e){let{slug:t,environment:n,name:r,models:i=["*"],allowInvoke:s=!0,allowStreaming:a=!0,allowAsync:o=!1}=e,c=r||S({slug:t,environment:n,resourceType:"bedrock-policy"}),l=f(c),u=[];if(s)u.push("bedrock:InvokeModel");if(a)u.push("bedrock:InvokeModelWithResponseStream");if(o)u.push("bedrock:InvokeModelAsync");let m=i.map((g)=>g==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${g}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:u,Resource:m}]}}},logicalId:l}}static enableBedrockForLambda(e){return bt.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return bt.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return bt.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,t=["*"],n=!0){let r=["bedrock:InvokeModel"];if(n)r.push("bedrock:InvokeModelWithResponseStream");let i=t.map((s)=>s==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${s}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:r,Resource:i}]}}),e}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 zt{static createPostgres(e){return zt.createRDSInstance("postgres","16.2",e)}static createMysql(e){return zt.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,t,n){let{slug:r,environment:i,instanceClass:s="db.t3.micro",allocatedStorage:a=20,storageType:o="gp3",masterUsername:c="admin",masterPassword:l,databaseName:u,subnetIds:m,securityGroupIds:p,encrypted:g=!0,kmsKeyId:y,multiAz:h=!1,backupRetentionDays:b=7,publiclyAccessible:C=!1,enableCloudwatchLogs:T=!0,deletionProtection:A=!0}=n,R=S({slug:r,environment:i,resourceType:`${e}-db`}),P=f(R),E,w;if(m&&m.length>0){let D=S({slug:r,environment:i,resourceType:"db-subnet-group"});w=f(D),E={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:D,DBSubnetGroupDescription:`Subnet group for ${R}`,SubnetIds:m,Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:i}]}}}let I={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:R,DBInstanceClass:s,Engine:e,EngineVersion:t,MasterUsername:c,MasterUserPassword:l,AllocatedStorage:a,StorageType:o,StorageEncrypted:g,MultiAZ:h,BackupRetentionPeriod:b,PubliclyAccessible:C,DeletionProtection:A,Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:i}]}};if(u)I.Properties.DBName=u;if(y)I.Properties.KmsKeyId=y;if(w)I.Properties.DBSubnetGroupName=v.Ref(w);if(p&&p.length>0)I.Properties.VPCSecurityGroups=p;if(T)I.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:I,subnetGroup:E,logicalId:P,subnetGroupId:w}}static createReadReplica(e,t){let{slug:n,environment:r,instanceClass:i="db.t3.micro",securityGroupIds:s,publiclyAccessible:a=!1}=t,o=S({slug:n,environment:r,resourceType:"db-replica"}),c=f(o),l={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:o,DBInstanceClass:i,SourceDBInstanceIdentifier:v.Ref(e),PubliclyAccessible:a,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r},{Key:"Type",Value:"ReadReplica"}]}};if(s&&s.length>0)l.Properties.VPCSecurityGroups=s;return{replica:l,logicalId:c}}static createParameterGroup(e,t,n){let{slug:r,environment:i,parameters:s={}}=n,a=S({slug:r,environment:i,resourceType:"db-params"}),o=f(a),c=e==="postgres"?`postgres${t.split(".")[0]}`:`mysql${t.split(".")[0]}.${t.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:a,Description:`Parameter group for ${a}`,Family:c,Parameters:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i}]}},logicalId:o}}static enableBackup(e,t=7){return e.Properties.BackupRetentionPeriod=t,e}static createTable(e){let{slug:t,environment:n,tableName:r,partitionKey:i,sortKey:s,billingMode:a="PAY_PER_REQUEST",readCapacity:o=5,writeCapacity:c=5,streamEnabled:l=!1,streamViewType:u="NEW_AND_OLD_IMAGES",encrypted:m=!0,kmsKeyId:p,pointInTimeRecovery:g=!0,ttlAttribute:y}=e,h=r||S({slug:t,environment:n,resourceType:"table"}),b=f(h),C=[{AttributeName:i.name,AttributeType:i.type}];if(s)C.push({AttributeName:s.name,AttributeType:s.type});let T=[{AttributeName:i.name,KeyType:"HASH"}];if(s)T.push({AttributeName:s.name,KeyType:"RANGE"});let A={Type:"AWS::DynamoDB::Table",Properties:{TableName:h,BillingMode:a,AttributeDefinitions:C,KeySchema:T,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:n}]}};if(a==="PROVISIONED")A.Properties.ProvisionedThroughput={ReadCapacityUnits:o,WriteCapacityUnits:c};if(l)A.Properties.StreamSpecification={StreamViewType:u};if(m)A.Properties.SSESpecification={SSEEnabled:!0,SSEType:p?"KMS":"AES256",KMSMasterKeyId:p};if(g)A.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(y)A.Properties.TimeToLiveSpecification={AttributeName:y,Enabled:!0};return{table:A,logicalId:b}}static addGlobalSecondaryIndex(e,t){let{indexName:n,partitionKey:r,sortKey:i,projectionType:s="ALL",nonKeyAttributes:a,readCapacity:o=5,writeCapacity:c=5}=t;if(!e.Properties.AttributeDefinitions.some((m)=>m.AttributeName===r.name))e.Properties.AttributeDefinitions.push({AttributeName:r.name,AttributeType:r.type});if(i&&!e.Properties.AttributeDefinitions.some((m)=>m.AttributeName===i.name))e.Properties.AttributeDefinitions.push({AttributeName:i.name,AttributeType:i.type});let l=[{AttributeName:r.name,KeyType:"HASH"}];if(i)l.push({AttributeName:i.name,KeyType:"RANGE"});let u={IndexName:n,KeySchema:l,Projection:{ProjectionType:s,NonKeyAttributes:s==="INCLUDE"?a:void 0},ProvisionedThroughput:void 0};if(e.Properties.BillingMode==="PROVISIONED")u.ProvisionedThroughput={ReadCapacityUnits:o,WriteCapacityUnits:c};if(!e.Properties.GlobalSecondaryIndexes)e.Properties.GlobalSecondaryIndexes=[];return e.Properties.GlobalSecondaryIndexes.push(u),e}static enableStreams(e,t="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:t},e}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 Ea{static createRedis(e){let{slug:t,environment:n,nodeType:r="cache.t3.micro",engineVersion:i="7.1",port:s=6379,subnetIds:a,securityGroupIds:o,numCacheClusters:c=2,automaticFailover:l=!0,multiAz:u=!0,clusterMode:m=!1,numNodeGroups:p=1,replicasPerNodeGroup:g=1,atRestEncryption:y=!0,transitEncryption:h=!0,authToken:b,kmsKeyId:C,snapshotRetentionDays:T=7,snapshotWindow:A,maintenanceWindow:R}=e,P=S({slug:t,environment:n,resourceType:"redis"}),E=f(P),w,I;if(a&&a.length>0){let k=S({slug:t,environment:n,resourceType:"cache-subnet-group"});I=f(k),w={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:k,Description:`Subnet group for ${P}`,SubnetIds:a,Tags:[{Key:"Name",Value:k},{Key:"Environment",Value:n}]}}}let D={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:P,ReplicationGroupDescription:`Redis cluster for ${t} ${n}`,Engine:"redis",EngineVersion:i,CacheNodeType:r,Port:s,AutomaticFailoverEnabled:l,MultiAZEnabled:u,AtRestEncryptionEnabled:y,TransitEncryptionEnabled:h,SnapshotRetentionLimit:T,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:n}]}};if(m)D.Properties.NumNodeGroups=p,D.Properties.ReplicasPerNodeGroup=g;else D.Properties.NumCacheClusters=c;if(b)D.Properties.AuthToken=b;if(C)D.Properties.KmsKeyId=C;if(I)D.Properties.CacheSubnetGroupName=v.Ref(I);if(o&&o.length>0)D.Properties.SecurityGroupIds=o;if(A)D.Properties.SnapshotWindow=A;if(R)D.Properties.PreferredMaintenanceWindow=R;return{replicationGroup:D,subnetGroup:w,logicalId:E,subnetGroupId:I}}static createMemcached(e){let{slug:t,environment:n,nodeType:r="cache.t3.micro",engineVersion:i="1.6.22",port:s=11211,numCacheNodes:a=2,subnetIds:o,securityGroupIds:c,azMode:l="cross-az",preferredAzs:u,maintenanceWindow:m}=e,p=S({slug:t,environment:n,resourceType:"memcached"}),g=f(p),y,h;if(o&&o.length>0){let C=S({slug:t,environment:n,resourceType:"cache-subnet-group"});h=f(C),y={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:C,Description:`Subnet group for ${p}`,SubnetIds:o,Tags:[{Key:"Name",Value:C},{Key:"Environment",Value:n}]}}}let b={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:p,CacheNodeType:r,Engine:"memcached",EngineVersion:i,NumCacheNodes:a,Port:s,AZMode:l,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:n}]}};if(h)b.Properties.CacheSubnetGroupName=v.Ref(h);if(c&&c.length>0)b.Properties.VpcSecurityGroupIds=c;if(u&&u.length>0)b.Properties.PreferredAvailabilityZones=u;if(m)b.Properties.PreferredMaintenanceWindow=m;return{cluster:b,subnetGroup:y,logicalId:g,subnetGroupId:h}}static enableClusterMode(e,t=3,n=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=t,e.Properties.ReplicasPerNodeGroup=n,e}static createRedisParameterGroup(e,t){let{slug:n,environment:r,parameters:i={}}=t,s=S({slug:n,environment:r,resourceType:"redis-params"}),a=f(s);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${s}`,Properties:i,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},logicalId:a}}static createMemcachedParameterGroup(e,t){let{slug:n,environment:r,parameters:i={}}=t,s=S({slug:n,environment:r,resourceType:"memcached-params"}),a=f(s);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${s}`,Properties:i,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},logicalId:a}}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 le{static createUser(e){let{slug:t,environment:n,userName:r,groups:i,managedPolicyArns:s}=e,a=r||S({slug:t,environment:n,resourceType:"user"}),o=f(a),c={Type:"AWS::IAM::User",Properties:{UserName:a,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:n}]}};if(i&&i.length>0)c.Properties.Groups=i;if(s&&s.length>0)c.Properties.ManagedPolicyArns=s;return{user:c,logicalId:o}}static createRole(e){let{slug:t,environment:n,roleName:r,servicePrincipal:i,awsPrincipal:s,managedPolicyArns:a}=e,o=r||S({slug:t,environment:n,resourceType:"role"}),c=f(o),l={};if(i)l.Service=i;if(s)l.AWS=s;let u={Type:"AWS::IAM::Role",Properties:{RoleName:o,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:l,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}};if(a&&a.length>0)u.Properties.ManagedPolicyArns=a;return{role:u,logicalId:c}}static createGroup(e){let{slug:t,environment:n,groupName:r,managedPolicyArns:i}=e,s=r||S({slug:t,environment:n,resourceType:"group"}),a=f(s),o={Type:"AWS::IAM::Group",Properties:{GroupName:s}};if(i&&i.length>0)o.Properties.ManagedPolicyArns=i;return{group:o,logicalId:a}}static createPolicy(e){let{slug:t,environment:n,policyName:r,description:i,statements:s}=e,a=r||S({slug:t,environment:n,resourceType:"policy"}),o=f(a),c=s.map((u)=>({Sid:u.sid,Effect:u.effect||"Allow",Action:u.actions,Resource:u.resources,Condition:u.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:a,Description:i||`Managed policy for ${a}`,PolicyDocument:{Version:"2012-10-17",Statement:c}}},logicalId:o}}static attachPolicyToRole(e,t){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(t))e.Properties.ManagedPolicyArns.push(t);return e}static attachPolicyToUser(e,t){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(t))e.Properties.ManagedPolicyArns.push(t);return e}static attachPolicyToGroup(e,t){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(t))e.Properties.ManagedPolicyArns.push(t);return e}static addInlinePolicyToRole(e,t,n){if(!e.Properties.Policies)e.Properties.Policies=[];let r=n.map((i)=>({Effect:i.effect||"Allow",Action:i.actions,Resource:i.resources}));return e.Properties.Policies.push({PolicyName:t,PolicyDocument:{Version:"2012-10-17",Statement:r}}),e}static addInlinePolicyToUser(e,t,n){if(!e.Properties.Policies)e.Properties.Policies=[];let r=n.map((i)=>({Effect:i.effect||"Allow",Action:i.actions,Resource:i.resources}));return e.Properties.Policies.push({PolicyName:t,PolicyDocument:{Version:"2012-10-17",Statement:r}}),e}static createAccessKey(e,t){let{slug:n,environment:r,status:i="Active"}=t,s=S({slug:n,environment:r,resourceType:"access-key"}),a=f(s);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:v.Ref(e),Status:i}},logicalId:a}}static createInstanceProfile(e,t){let{slug:n,environment:r,profileName:i}=t,s=i||S({slug:n,environment:r,resourceType:"instance-profile"}),a=f(s);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:s,Roles:[v.Ref(e)]}},logicalId:a}}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(e){let{slug:t,environment:n,permissions:r,createAccessKey:i=!0}=e,s={},a=[];if(r.s3Buckets&&r.s3Buckets.length>0)a.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...r.s3Buckets,...r.s3Buckets.map((g)=>`${g}/*`)]});if(r.cloudFrontDistributions&&r.cloudFrontDistributions.length>0)a.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:r.cloudFrontDistributions});if(r.ecrRepositories&&r.ecrRepositories.length>0)a.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:r.ecrRepositories}),a.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(r.ecsServices&&r.ecsServices.length>0)a.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:r.ecsServices}),a.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),a.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(r.cloudFormationStacks&&r.cloudFormationStacks.length>0)a.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:r.cloudFormationStacks});if(r.lambdaFunctions&&r.lambdaFunctions.length>0)a.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:r.lambdaFunctions});if(r.secretsManagerSecrets&&r.secretsManagerSecrets.length>0)a.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:r.secretsManagerSecrets});let{policy:o,logicalId:c}=le.createPolicy({slug:t,environment:n,policyName:S({slug:t,environment:n,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${t} (${n})`,statements:a});s[c]=o;let{user:l,logicalId:u}=le.createUser({slug:t,environment:n,userName:S({slug:t,environment:n,resourceType:"cicd-user"}),managedPolicyArns:[v.Ref(c)]});s[u]=l;let m,p;if(i){let g=le.createAccessKey(u,{slug:t,environment:n});m=g.accessKey,p=g.logicalId,s[p]=m}return{user:l,accessKey:m,policy:o,userLogicalId:u,accessKeyLogicalId:p,policyLogicalId:c,resources:s}}static createCrossAccountRole(e){let{slug:t,environment:n,trustedAccountIds:r,externalId:i,permissions:s,maxSessionDuration:a=3600}=e,o={},{policy:c,logicalId:l}=le.createPolicy({slug:t,environment:n,policyName:S({slug:t,environment:n,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${t} (${n})`,statements:s});o[l]=c;let u=S({slug:t,environment:n,resourceType:"cross-account-role"}),m=f(u),p={};if(i)p.StringEquals={"sts:ExternalId":i};let g={Type:"AWS::IAM::Role",Properties:{RoleName:u,MaxSessionDuration:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:r.map((y)=>`arn:aws:iam::${y}:root`)},Action:"sts:AssumeRole",...Object.keys(p).length>0?{Condition:p}:{}}]},ManagedPolicyArns:[v.Ref(l)],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n},{Key:"Purpose",Value:"Cross-Account Access"}]}};return o[m]=g,{role:g,policy:c,roleLogicalId:m,policyLogicalId:l,resources:o}}static createCliUser(e){let{slug:t,environment:n,permissions:r="readonly"}=e,i={},s=[],a=[];switch(r){case"readonly":a=[le.ManagedPolicies.ReadOnlyAccess];break;case"deploy":s=[{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":a=[le.ManagedPolicies.AdministratorAccess];break}let o,c;if(s.length>0){let g=le.createPolicy({slug:t,environment:n,policyName:S({slug:t,environment:n,resourceType:"cli-policy"}),description:`CLI access policy for ${t} (${n})`,statements:s});o=g.policy,c=g.logicalId,i[c]=o,a=[v.Ref(c)]}let{user:l,logicalId:u}=le.createUser({slug:t,environment:n,userName:S({slug:t,environment:n,resourceType:"cli-user"}),managedPolicyArns:a});i[u]=l;let{accessKey:m,logicalId:p}=le.createAccessKey(u,{slug:t,environment:n});return i[p]=m,{user:l,accessKey:m,policy:o,userLogicalId:u,accessKeyLogicalId:p,policyLogicalId:c,resources:i}}static CiCdPolicies={s3Deployment:(e)=>[{sid:"S3ListBuckets",actions:["s3:ListBucket","s3:GetBucketLocation"],resources:e},{sid:"S3Objects",actions:["s3:GetObject","s3:PutObject","s3:DeleteObject"],resources:e.map((t)=>`${t}/*`)}],cloudFrontInvalidation:(e)=>[{sid:"CloudFrontInvalidation",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations"],resources:e}],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:(e)=>[{sid:"ECRAuth",actions:["ecr:GetAuthorizationToken"],resources:"*"},{sid:"ECRPush",actions:["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:e}],lambdaDeployment:(e)=>[{sid:"LambdaDeploy",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion"],resources:e}],cloudFormationDeployment:(e)=>[{sid:"CloudFormationDeploy",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate"],resources:e}]}}class wa{static createRestApi(e){let{slug:t,environment:n,name:r,description:i,endpointType:s="REGIONAL",binaryMediaTypes:a,compressionSize:o}=e,c=r||S({slug:t,environment:n,resourceType:"rest-api"}),l=f(c),u={Type:"AWS::ApiGateway::RestApi",Properties:{Name:c,Description:i||`REST API for ${t} ${n}`,EndpointConfiguration:{Types:[s]},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:n}]}};if(a&&a.length>0)u.Properties.BinaryMediaTypes=a;if(o!==void 0)u.Properties.MinimumCompressionSize=o;return{restApi:u,logicalId:l}}static createHttpApi(e){let{slug:t,environment:n,name:r,description:i,corsEnabled:s=!0,corsOrigins:a=["*"],corsMethods:o=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:c=["*"],corsMaxAge:l=86400,corsAllowCredentials:u=!1}=e,m=r||S({slug:t,environment:n,resourceType:"http-api"}),p=f(m),g={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:m,Description:i||`HTTP API for ${t} ${n}`,ProtocolType:"HTTP",Tags:{Name:m,Environment:n}}};if(s)g.Properties.CorsConfiguration={AllowOrigins:a,AllowMethods:o,AllowHeaders:c,MaxAge:l,AllowCredentials:u};return{httpApi:g,logicalId:p}}static createWebSocketApi(e){let{slug:t,environment:n,name:r,description:i}=e,s=r||S({slug:t,environment:n,resourceType:"ws-api"}),a=f(s);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:s,Description:i||`WebSocket API for ${t} ${n}`,ProtocolType:"WEBSOCKET",Tags:{Name:s,Environment:n}}},logicalId:a}}static createDeployment(e,t){let{slug:n,environment:r,description:i}=t,s=S({slug:n,environment:r,resourceType:"api-deployment"}),a=f(s);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:v.Ref(e),Description:i||`Deployment for ${s}`}},logicalId:a}}static createStage(e,t,n){let{slug:r,environment:i,stageName:s,description:a,cacheEnabled:o=!1,cacheSize:c="0.5",variables:l,throttling:u}=n,m=S({slug:r,environment:i,resourceType:"api-stage"}),p=f(m),g={Type:"AWS::ApiGateway::Stage",Properties:{StageName:s||i,RestApiId:v.Ref(e),DeploymentId:v.Ref(t),Description:a,CacheClusterEnabled:o,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:i}]}};if(o)g.Properties.CacheClusterSize=c;if(l)g.Properties.Variables=l;if(u)g.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:u.burstLimit,ThrottlingRateLimit:u.rateLimit}];return{stage:g,logicalId:p}}static createAuthorizer(e,t){let{slug:n,environment:r,name:i,type:s,functionArn:a,identitySource:o,userPoolArns:c,ttl:l=300}=t,u=i||S({slug:n,environment:r,resourceType:"api-authorizer"}),m=f(u),p={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:u,Type:s,RestApiId:v.Ref(e),AuthorizerResultTtlInSeconds:l}};if(s==="TOKEN"||s==="REQUEST"){if(!a)throw Error("Lambda authorizer requires functionArn");p.Properties.AuthorizerUri=a,p.Properties.IdentitySource=o||"method.request.header.Authorization"}if(s==="COGNITO_USER_POOLS"){if(!c||c.length===0)throw Error("Cognito authorizer requires userPoolArns");p.Properties.ProviderARNs=c,p.Properties.IdentitySource=o||"method.request.header.Authorization"}return{authorizer:p,logicalId:m}}static setCors(e,t={}){let{origins:n=["*"],methods:r=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:i=["*"],maxAge:s=86400,allowCredentials:a=!1}=t;return e.Properties.CorsConfiguration={AllowOrigins:n,AllowMethods:r,AllowHeaders:i,MaxAge:s,AllowCredentials:a},e}static addThrottling(e,t=5000,n=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:t,ThrottlingRateLimit:n}),e}static enableCaching(e,t="0.5",n=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=t,!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:n}),e}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 re{static createTopic(e){let{slug:t,environment:n,topicName:r,displayName:i,encrypted:s=!1,kmsKeyId:a}=e,o=r||S({slug:t,environment:n,resourceType:"topic"}),c=f(o),l={Type:"AWS::SNS::Topic",Properties:{TopicName:o,DisplayName:i||o,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}};if(s&&a)l.Properties.KmsMasterKeyId=a;return{topic:l,logicalId:c}}static subscribe(e,t){let{slug:n,environment:r,protocol:i,endpoint:s,filterPolicy:a,rawMessageDelivery:o=!1}=t,c=S({slug:n,environment:r,resourceType:"subscription"}),l=s.replace(/[^a-zA-Z0-9]/g,""),u=l.length>12?l.slice(-12):l,m=f(`${c}-${i}-${u}`),p={Type:"AWS::SNS::Subscription",Properties:{TopicArn:v.Ref(e),Protocol:i,Endpoint:s,RawMessageDelivery:o}};if(a)p.Properties.FilterPolicy=a;return{subscription:p,logicalId:m}}static subscribeEmail(e,t,n){return re.subscribe(e,{...n,protocol:"email",endpoint:t})}static subscribeLambda(e,t,n){return re.subscribe(e,{...n,protocol:"lambda",endpoint:t,rawMessageDelivery:!0})}static subscribeSqs(e,t,n){return re.subscribe(e,{...n,protocol:"sqs",endpoint:t})}static subscribeHttp(e,t,n){let r=t.startsWith("https://")?"https":"http";return re.subscribe(e,{...n,protocol:r,endpoint:t})}static subscribeSms(e,t,n){return re.subscribe(e,{...n,protocol:"sms",endpoint:t})}static setTopicPolicy(e,t){let{slug:n,environment:r,allowedPrincipals:i,allowedServices:s,actions:a="SNS:Publish"}=t,o=S({slug:n,environment:r,resourceType:"topic-policy"}),c=f(o),l={};if(i)l.AWS=i;if(s)l.Service=s;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[v.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:l,Action:a,Resource:v.Ref(e)}]}}},logicalId:c}}static allowCloudWatchAlarms(e,t){return re.setTopicPolicy(e,{...t,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,t){return re.setTopicPolicy(e,{...t,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,t){return re.setTopicPolicy(e,{...t,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,t){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=t,e}static addInlineSubscription(e,t,n){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:t,Endpoint:n}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,t,n)=>({[e]:[{numeric:[">=",t,"<=",n]}]}),prefix:(e,t)=>({[e]:[{prefix:t}]}),and:(...e)=>Object.assign({},...e),exists:(e,t)=>({[e]:[{exists:t}]})};static UseCases={createAlertTopic:(e)=>re.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>re.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>re.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class Ia{static createStateMachine(e){let{slug:t,environment:n,stateMachineName:r,type:i="STANDARD",definition:s,roleArn:a,loggingConfiguration:o,tracingConfiguration:c}=e,l=r||S({slug:t,environment:n,resourceType:"state-machine"}),u=f(l),m,p,g;if(a)g=a;else{let h=S({slug:t,environment:n,resourceType:"state-machine-role"});p=f(h),m={Type:"AWS::IAM::Role",Properties:{RoleName:h,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:h},{Key:"Environment",Value:n}]}},g=v.GetAtt(p,"Arn")}let y={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:l,StateMachineType:i,DefinitionString:JSON.stringify(s),RoleArn:g,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:n}]}};if(o)y.Properties.LoggingConfiguration={Level:o.level,IncludeExecutionData:o.includeExecutionData,Destinations:o.destinations?.map((h)=>({CloudWatchLogsLogGroup:{LogGroupArn:h}}))};if(c)y.Properties.TracingConfiguration={Enabled:c.enabled};return{stateMachine:y,logicalId:u,role:m,roleLogicalId:p}}static createLambdaTask(e,t){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:t?.parameters||{"Input.$":"$"}},ResultPath:t?.resultPath,Retry:t?.retry,Catch:t?.catch,Next:t?.next,End:t?.end}}static createDynamoDBTask(e,t,n,r){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"}[e],Parameters:{TableName:t,...n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSNSPublishTask(e,t,n){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:t},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createSQSSendMessageTask(e,t,n){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:t},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createPassState(e){return{Type:"Pass",Result:e?.result,ResultPath:e?.resultPath,Parameters:e?.parameters,Next:e?.next,End:e?.end}}static createWaitState(e){return{Type:"Wait",Seconds:e.seconds,Timestamp:e.timestamp,SecondsPath:e.secondsPath,TimestampPath:e.timestampPath,Next:e.next,End:e.end}}static createChoiceState(e,t){return{Type:"Choice",Choices:e,Default:t}}static createParallelState(e,t){return{Type:"Parallel",Branches:e,ResultPath:t?.resultPath,Retry:t?.retry,Catch:t?.catch,Next:t?.next,End:t?.end}}static createMapState(e,t){return{Type:"Map",ItemsPath:t?.itemsPath||"$.items",Iterator:e,MaxConcurrency:t?.maxConcurrency,ResultPath:t?.resultPath,Retry:t?.retry,Catch:t?.catch,Next:t?.next,End:t?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,t){return{Type:"Fail",Error:e,Cause:t}}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:(e,t,n,r)=>({ErrorEquals:e,IntervalSeconds:t,MaxAttempts:n,BackoffRate:r})};static CatchPolicies={all:(e,t)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:t||"$.error"}),specific:(e,t,n)=>({ErrorEquals:e,Next:t,ResultPath:n||"$.error"})};static Patterns={sequential:(e,t,n)=>{let r={};return n.forEach((i,s)=>{let a=s===n.length-1;r[i.name]={...i.state,Next:a?void 0:n[s+1].name,End:a}}),{Comment:"Sequential workflow",StartAt:n[0].name,States:r}},fanout:(e,t,n)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:n.map((r)=>r.definition),End:!0}}}),map:(e,t,n,r)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:n,MaxConcurrency:r,End:!0}}}),withErrorHandling:(e,t,n,r)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...n,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:r,Success:{Type:"Succeed"}}})}}class fr{static createAlarm(e){let{slug:t,environment:n,alarmName:r,metricName:i,namespace:s,statistic:a="Average",period:o=300,evaluationPeriods:c=1,threshold:l,comparisonOperator:u,treatMissingData:m="notBreaching",actionsEnabled:p=!0,alarmActions:g,okActions:y,insufficientDataActions:h,dimensions:b,unit:C,datapointsToAlarm:T}=e,A=r||S({slug:t,environment:n,resourceType:"alarm"}),R=f(A),P={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:A,MetricName:i,Namespace:s,Statistic:a,Period:o,EvaluationPeriods:c,Threshold:l,ComparisonOperator:u,TreatMissingData:m,ActionsEnabled:p}};if(g&&g.length>0)P.Properties.AlarmActions=g;if(y&&y.length>0)P.Properties.OKActions=y;if(h&&h.length>0)P.Properties.InsufficientDataActions=h;if(b)P.Properties.Dimensions=Object.entries(b).map(([E,w])=>({Name:E,Value:w}));if(C)P.Properties.Unit=C;if(T!==void 0)P.Properties.DatapointsToAlarm=T;return{alarm:P,logicalId:R}}static createCompositeAlarm(e){let{slug:t,environment:n,alarmName:r,alarmRule:i,actionsEnabled:s=!0,alarmActions:a,okActions:o,insufficientDataActions:c}=e,l=r||S({slug:t,environment:n,resourceType:"composite-alarm"}),u=f(l),m={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:l,AlarmRule:i,ActionsEnabled:s}};if(a&&a.length>0)m.Properties.AlarmActions=a;if(o&&o.length>0)m.Properties.OKActions=o;if(c&&c.length>0)m.Properties.InsufficientDataActions=c;return{alarm:m,logicalId:u}}static createDashboard(e){let{slug:t,environment:n,dashboardName:r,widgets:i}=e,s=r||S({slug:t,environment:n,resourceType:"dashboard"}),a=f(s),o={widgets:i.map((l)=>({type:l.type,x:l.x,y:l.y,width:l.width,height:l.height,properties:l.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:s,DashboardBody:JSON.stringify(o)}},logicalId:a}}static createLogGroup(e){let{slug:t,environment:n,logGroupName:r,retentionInDays:i,kmsKeyId:s}=e,a=r||S({slug:t,environment:n,resourceType:"log-group"}),o=f(a),c={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:a}};if(i!==void 0)c.Properties.RetentionInDays=i;if(s)c.Properties.KmsKeyId=s;return{logGroup:c,logicalId:o}}static createLogStream(e,t){let{slug:n,environment:r,logStreamName:i}=t,s=i||S({slug:n,environment:r,resourceType:"log-stream"}),a=f(s);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:v.Ref(e),LogStreamName:s}},logicalId:a}}static createMetricFilter(e,t){let{slug:n,environment:r,filterName:i,filterPattern:s,metricTransformations:a}=t,o=i||S({slug:n,environment:r,resourceType:"metric-filter"}),c=f(o);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:v.Ref(e),FilterPattern:s,MetricTransformations:a.map((u)=>({MetricName:u.metricName,MetricNamespace:u.metricNamespace,MetricValue:u.metricValue,DefaultValue:u.defaultValue,Unit:u.unit}))}},logicalId:c}}static AlarmTypes={highCpu:(e,t,n,r=80,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:n},alarmActions:i?[i]:void 0}),highMemory:(e,t,n,r=80,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:n},alarmActions:i?[i]:void 0}),highDisk:(e,t,n,r=80,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:n,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:i?[i]:void 0}),lambdaErrors:(e,t,n,r=5,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:n},alarmActions:i?[i]:void 0}),lambdaThrottles:(e,t,n,r=10,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:n},alarmActions:i?[i]:void 0}),apiGateway5xxErrors:(e,t,n,r=10,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:n},alarmActions:i?[i]:void 0}),apiGateway4xxErrors:(e,t,n,r=50,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:n},alarmActions:i?[i]:void 0}),dynamoDBThrottles:(e,t,n,r=5,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:n},alarmActions:i?[i]:void 0}),rdsCpu:(e,t,n,r=80,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:n},alarmActions:i?[i]:void 0}),rdsFreeStorage:(e,t,n,r=5368709120,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:n},alarmActions:i?[i]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,t,n,r=100,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:n},alarmActions:i?[i]:void 0}),albUnhealthyTargets:(e,t,n,r,i=1,s)=>({slug:e,environment:t,alarmName:`${e}-${t}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:n,TargetGroup:r},alarmActions:s?[s]:void 0}),sesBounceRate:(e,t,n=5,r)=>({slug:e,environment:t,alarmName:`${e}-${t}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:n/100,comparisonOperator:"GreaterThanThreshold",alarmActions:r?[r]:void 0}),sesComplaintRate:(e,t,n=0.1,r)=>({slug:e,environment:t,alarmName:`${e}-${t}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:n/100,comparisonOperator:"GreaterThanThreshold",alarmActions:r?[r]:void 0}),smsDeliveryFailure:(e,t,n,r=10,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:n},alarmActions:i?[i]:void 0}),smsSpendLimit:(e,t,n=100,r)=>({slug:e,environment:t,alarmName:`${e}-${t}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",alarmActions:r?[r]:void 0}),connectMissedCalls:(e,t,n,r=5,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:n},alarmActions:i?[i]:void 0})};static DashboardWidgets={metric:(e,t,n,r,i,s)=>({type:"metric",x:e,y:t,width:n,height:r,properties:{metrics:i,title:s||"Metrics",region:"us-east-1",period:300}}),text:(e,t,n,r,i)=>({type:"text",x:e,y:t,width:n,height:r,properties:{markdown:i}}),log:(e,t,n,r,i,s)=>({type:"log",x:e,y:t,width:n,height:r,properties:{query:`SOURCE '${i.join("' | SOURCE '")}'
2287
2287
  | fields @timestamp, @message
2288
2288
  | sort @timestamp desc
2289
2289
  | limit 20`,region:"us-east-1",title:s||"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:(e,t)=>`{ $.${e} = "${t}" }`,httpStatus:(e)=>`[..., status_code = ${e}, ...]`,http4xx:"[..., status_code = 4*, ...]",http5xx:"[..., status_code = 5*, ...]"};static createApplicationDashboard(e){let{slug:t,environment:n,region:r="us-east-1",components:i={}}=e,s=[],a=0;if(s.push({type:"text",x:0,y:a,width:24,height:1,properties:{markdown:`# ${t.toUpperCase()} Dashboard (${n})`}}),a+=1,i.ec2InstanceIds&&i.ec2InstanceIds.length>0)s.push({type:"text",x:0,y:a,width:24,height:1,properties:{markdown:"## EC2 Instances"}}),a+=1,s.push({type:"metric",x:0,y:a,width:8,height:6,properties:{title:"CPU Utilization",region:r,metrics:i.ec2InstanceIds.map((o)=>["AWS/EC2","CPUUtilization","InstanceId",o]),period:300,stat:"Average"}}),s.push({type:"metric",x:8,y:a,width:8,height:6,properties:{title:"Network Traffic",region:r,metrics:[...i.ec2InstanceIds.flatMap((o)=>[["AWS/EC2","NetworkIn","InstanceId",o,{label:`${o} In`}],["AWS/EC2","NetworkOut","InstanceId",o,{label:`${o} Out`}]])],period:300,stat:"Sum"}}),s.push({type:"metric",x:16,y:a,width:8,height:6,properties:{title:"Status Checks",region:r,metrics:i.ec2InstanceIds.map((o)=>["AWS/EC2","StatusCheckFailed","InstanceId",o]),period:60,stat:"Maximum"}}),a+=6;if(i.lambdaFunctionNames&&i.lambdaFunctionNames.length>0)s.push({type:"text",x:0,y:a,width:24,height:1,properties:{markdown:"## Lambda Functions"}}),a+=1,s.push({type:"metric",x:0,y:a,width:8,height:6,properties:{title:"Invocations",region:r,metrics:i.lambdaFunctionNames.map((o)=>["AWS/Lambda","Invocations","FunctionName",o]),period:300,stat:"Sum"}}),s.push({type:"metric",x:8,y:a,width:8,height:6,properties:{title:"Duration",region:r,metrics:i.lambdaFunctionNames.map((o)=>["AWS/Lambda","Duration","FunctionName",o]),period:300,stat:"Average"}}),s.push({type:"metric",x:16,y:a,width:8,height:6,properties:{title:"Errors",region:r,metrics:i.lambdaFunctionNames.map((o)=>["AWS/Lambda","Errors","FunctionName",o]),period:300,stat:"Sum"}}),a+=6;if(i.ecsClusterName&&i.ecsServiceName)s.push({type:"text",x:0,y:a,width:24,height:1,properties:{markdown:"## ECS Service"}}),a+=1,s.push({type:"metric",x:0,y:a,width:8,height:6,properties:{title:"CPU Utilization",region:r,metrics:[["AWS/ECS","CPUUtilization","ClusterName",i.ecsClusterName,"ServiceName",i.ecsServiceName]],period:300,stat:"Average"}}),s.push({type:"metric",x:8,y:a,width:8,height:6,properties:{title:"Memory Utilization",region:r,metrics:[["AWS/ECS","MemoryUtilization","ClusterName",i.ecsClusterName,"ServiceName",i.ecsServiceName]],period:300,stat:"Average"}}),s.push({type:"metric",x:16,y:a,width:8,height:6,properties:{title:"Running Tasks",region:r,metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",i.ecsClusterName,"ServiceName",i.ecsServiceName]],period:60,stat:"Average"}}),a+=6;if(i.albName)s.push({type:"text",x:0,y:a,width:24,height:1,properties:{markdown:"## Application Load Balancer"}}),a+=1,s.push({type:"metric",x:0,y:a,width:8,height:6,properties:{title:"Request Count",region:r,metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",i.albName]],period:60,stat:"Sum"}}),s.push({type:"metric",x:8,y:a,width:8,height:6,properties:{title:"Response Time",region:r,metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",i.albName]],period:60,stat:"Average"}}),s.push({type:"metric",x:16,y:a,width:8,height:6,properties:{title:"HTTP Errors",region:r,metrics:[["AWS/ApplicationELB","HTTPCode_Target_4XX_Count","LoadBalancer",i.albName,{label:"4XX"}],["AWS/ApplicationELB","HTTPCode_Target_5XX_Count","LoadBalancer",i.albName,{label:"5XX"}]],period:60,stat:"Sum"}}),a+=6;if(i.rdsInstanceId)s.push({type:"text",x:0,y:a,width:24,height:1,properties:{markdown:"## RDS Database"}}),a+=1,s.push({type:"metric",x:0,y:a,width:8,height:6,properties:{title:"CPU Utilization",region:r,metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",i.rdsInstanceId]],period:300,stat:"Average"}}),s.push({type:"metric",x:8,y:a,width:8,height:6,properties:{title:"Database Connections",region:r,metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",i.rdsInstanceId]],period:60,stat:"Sum"}}),s.push({type:"metric",x:16,y:a,width:8,height:6,properties:{title:"Free Storage Space",region:r,metrics:[["AWS/RDS","FreeStorageSpace","DBInstanceIdentifier",i.rdsInstanceId]],period:300,stat:"Average"}}),a+=6;if(i.sqsQueueNames&&i.sqsQueueNames.length>0)s.push({type:"text",x:0,y:a,width:24,height:1,properties:{markdown:"## SQS Queues"}}),a+=1,s.push({type:"metric",x:0,y:a,width:12,height:6,properties:{title:"Messages Visible",region:r,metrics:i.sqsQueueNames.map((o)=>["AWS/SQS","ApproximateNumberOfMessagesVisible","QueueName",o]),period:60,stat:"Sum"}}),s.push({type:"metric",x:12,y:a,width:12,height:6,properties:{title:"Message Age",region:r,metrics:i.sqsQueueNames.map((o)=>["AWS/SQS","ApproximateAgeOfOldestMessage","QueueName",o]),period:60,stat:"Maximum"}}),a+=6;if(i.logGroupNames&&i.logGroupNames.length>0)s.push({type:"text",x:0,y:a,width:24,height:1,properties:{markdown:"## Application Logs"}}),a+=1,s.push({type:"log",x:0,y:a,width:24,height:6,properties:{query:`SOURCE '${i.logGroupNames.join("' | SOURCE '")}'
2290
2290
  | fields @timestamp, @message
2291
2291
  | filter @message like /ERROR|WARN|Exception/
2292
2292
  | sort @timestamp desc
2293
- | limit 50`,region:r,title:"Recent Errors and Warnings"}}),a+=6;return fr.createDashboard({slug:t,environment:n,widgets:s})}static DashboardTemplates={staticWebsite:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.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",e.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",e.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",e.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",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:e.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",e.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:e.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",e.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",e.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",e.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",e.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",e.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...e.lambdaFunctionNames.map((t,n)=>({type:"metric",x:n%3*8,y:7+Math.floor(n/3)*6,width:8,height:6,properties:{title:`${t} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",t],["AWS/Lambda","Duration","FunctionName",t],["AWS/Lambda","Errors","FunctionName",t]],period:300,stat:"Sum"}}))]}),containerService:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Container Service Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"ECS CPU",region:e.region||"us-east-1",metrics:[["AWS/ECS","CPUUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"ECS Memory",region:e.region||"us-east-1",metrics:[["AWS/ECS","MemoryUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Running Tasks",region:e.region||"us-east-1",metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:0,y:7,width:8,height:6,properties:{title:"ALB Requests",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",e.albName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:7,width:8,height:6,properties:{title:"Response Time",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",e.albName]],period:60,stat:"Average"}},{type:"metric",x:16,y:7,width:8,height:6,properties:{title:"Healthy Hosts",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","HealthyHostCount","LoadBalancer",e.albName]],period:60,stat:"Average"}},...e.rdsInstanceId?[{type:"metric",x:0,y:13,width:12,height:6,properties:{title:"RDS CPU",region:e.region||"us-east-1",metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",e.rdsInstanceId]],period:300,stat:"Average"}},{type:"metric",x:12,y:13,width:12,height:6,properties:{title:"RDS Connections",region:e.region||"us-east-1",metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",e.rdsInstanceId]],period:60,stat:"Sum"}}]:[]]})};static Config={createAlarmConfig:(e)=>{let{metricName:t,namespace:n,threshold:r,comparisonOperator:i="GreaterThanThreshold",evaluationPeriods:s=1,period:a=300,statistic:o="Average",treatMissingData:c="missing"}=e;return{MetricName:t,Namespace:n,Threshold:r,ComparisonOperator:i,EvaluationPeriods:s,Period:a,Statistic:o,TreatMissingData:c}},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:(e=80)=>({metricName:"CPUUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(e=80)=>({metricName:"MemoryUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(e=10)=>({metricName:"Errors",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(e=5000)=>({metricName:"Duration",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(e=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(e=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(e=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class Y{static createUserPool(e){let{slug:t,environment:n,userPoolName:r,aliasAttributes:i,autoVerifiedAttributes:s,passwordPolicy:a,mfaConfiguration:o,emailConfiguration:c,smsConfiguration:l,lambdaTriggers:u,userPoolAddOns:m,accountRecoverySetting:p}=e,g=r||S({slug:t,environment:n,resourceType:"user-pool"}),y=f(g),h={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:g,Policies:a?{PasswordPolicy:{MinimumLength:a.minimumLength,RequireLowercase:a.requireLowercase,RequireUppercase:a.requireUppercase,RequireNumbers:a.requireNumbers,RequireSymbols:a.requireSymbols,TemporaryPasswordValidityDays:a.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:o,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(i&&i.length>0)h.Properties.UsernameAttributes=i;if(s&&s.length>0)h.Properties.AutoVerifiedAttributes=s;if(c)h.Properties.EmailConfiguration={EmailSendingAccount:c.emailSendingAccount,From:c.from,ReplyToEmailAddress:c.replyToEmailAddress,SourceArn:c.sourceArn,ConfigurationSet:c.configurationSet};if(l)h.Properties.SmsConfiguration={ExternalId:l.externalId,SnsCallerArn:l.snsCallerArn};if(u)h.Properties.LambdaConfig={PreSignUp:u.preSignUp,PostConfirmation:u.postConfirmation,PreAuthentication:u.preAuthentication,PostAuthentication:u.postAuthentication,CustomMessage:u.customMessage,DefineAuthChallenge:u.defineAuthChallenge,CreateAuthChallenge:u.createAuthChallenge,VerifyAuthChallengeResponse:u.verifyAuthChallengeResponse,PreTokenGeneration:u.preTokenGeneration,UserMigration:u.userMigration};if(m)h.Properties.UserPoolAddOns={AdvancedSecurityMode:m.advancedSecurityMode};if(p)h.Properties.AccountRecoverySetting={RecoveryMechanisms:p.recoveryMechanisms};return{userPool:h,logicalId:y}}static createUserPoolClient(e,t){let{slug:n,environment:r,clientName:i,generateSecret:s=!1,refreshTokenValidity:a,accessTokenValidity:o,idTokenValidity:c,tokenValidityUnits:l,readAttributes:u,writeAttributes:m,explicitAuthFlows:p,preventUserExistenceErrors:g,enableTokenRevocation:y,callbackURLs:h,logoutURLs:b,allowedOAuthFlows:v,allowedOAuthScopes:T,allowedOAuthFlowsUserPoolClient:A,supportedIdentityProviders:R}=t,P=i||S({slug:n,environment:r,resourceType:"user-pool-client"}),E=f(P);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:P,UserPoolId:C.Ref(e),GenerateSecret:s,RefreshTokenValidity:a,AccessTokenValidity:o,IdTokenValidity:c,TokenValidityUnits:l,ReadAttributes:u,WriteAttributes:m,ExplicitAuthFlows:p,PreventUserExistenceErrors:g,EnableTokenRevocation:y,CallbackURLs:h,LogoutURLs:b,AllowedOAuthFlows:v,AllowedOAuthScopes:T,AllowedOAuthFlowsUserPoolClient:A,SupportedIdentityProviders:R}},logicalId:E}}static createUserPoolDomain(e,t){let{slug:n,environment:r,domain:i,customDomainConfig:s}=t,a=S({slug:n,environment:r,resourceType:"user-pool-domain"}),o=f(a);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:i,UserPoolId:C.Ref(e),CustomDomainConfig:s}},logicalId:o}}static createIdentityPool(e){let{slug:t,environment:n,identityPoolName:r,allowUnauthenticatedIdentities:i=!1,cognitoIdentityProviders:s,supportedLoginProviders:a,samlProviderARNs:o,openIdConnectProviderARNs:c}=e,l=r||S({slug:t,environment:n,resourceType:"identity-pool"}),u=f(l);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:l,AllowUnauthenticatedIdentities:i,CognitoIdentityProviders:s,SupportedLoginProviders:a,SamlProviderARNs:o,OpenIdConnectProviderARNs:c}},logicalId:u}}static createIdentityPoolRoleAttachment(e,t){let{slug:n,environment:r,authenticatedRole:i,unauthenticatedRole:s,roleMappings:a}=t,o=S({slug:n,environment:r,resourceType:"identity-pool-role-attachment"}),c=f(o),l={authenticated:i};if(s)l.unauthenticated=s;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:C.Ref(e),Roles:l,RoleMappings:a}},logicalId:c}}static createAuthenticatedRole(e){let{slug:t,environment:n,identityPoolLogicalId:r}=e,i=S({slug:t,environment:n,resourceType:"cognito-authenticated-role"}),s=f(i);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:i,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":C.Ref(r)},"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:i},{Key:"Environment",Value:n}]}},logicalId:s}}static createUnauthenticatedRole(e){let{slug:t,environment:n,identityPoolLogicalId:r}=e,i=S({slug:t,environment:n,resourceType:"cognito-unauthenticated-role"}),s=f(i);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:i,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":C.Ref(r)},"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:i},{Key:"Environment",Value:n}]}},logicalId:s}}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:(e,t,n)=>{let{userPool:r,logicalId:i}=Y.createUserPool({slug:e,environment:t,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Y.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:s,logicalId:a}=Y.createUserPoolClient(i,{slug:e,environment:t,explicitAuthFlows:[...Y.AuthFlows.standard],callbackURLs:[n],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Y.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:r,poolId:i,client:s,clientId:a}},mobileApp:(e,t)=>{let{userPool:n,logicalId:r}=Y.createUserPool({slug:e,environment:t,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Y.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:i,logicalId:s}=Y.createUserPoolClient(r,{slug:e,environment:t,explicitAuthFlows:[...Y.AuthFlows.standard]}),{identityPool:a,logicalId:o}=Y.createIdentityPool({slug:e,environment:t,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:C.Ref(s),ProviderName:C.GetAtt(r,"ProviderName")}]}),{role:c,logicalId:l}=Y.createAuthenticatedRole({slug:e,environment:t,identityPoolLogicalId:o}),{attachment:u,logicalId:m}=Y.createIdentityPoolRoleAttachment(o,{slug:e,environment:t,authenticatedRole:C.GetAtt(l,"Arn")});return{userPool:n,poolId:r,client:i,clientId:s,identityPool:a,identityPoolId:o,authRole:c,authRoleId:l,attachment:u,attachmentId:m}}}}import{createHash as Da}from"node:crypto";import{copyFileSync as Na,existsSync as Qt,readdirSync as xa,readFileSync as bt,statSync as ka,writeFileSync as St}from"node:fs";import{basename as Ma,dirname as hr,extname as br,join as et}from"node:path";class Z{static createApplication(e){let{slug:t,environment:n,applicationName:r,computePlatform:i}=e,s=r||S({slug:t,environment:n,resourceType:"deploy-app"}),a=f(s);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:s,ComputePlatform:i,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:n}]}},logicalId:a}}static createDeploymentGroup(e,t){let{slug:n,environment:r,deploymentGroupName:i,serviceRoleArn:s,autoScalingGroups:a,ec2TagFilters:o,deploymentConfigName:c,autoRollbackConfiguration:l,alarmConfiguration:u,loadBalancerInfo:m,blueGreenDeploymentConfiguration:p}=t,g=i||S({slug:n,environment:r,resourceType:"deploy-group"}),y=f(g);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:C.Ref(e),DeploymentGroupName:g,ServiceRoleArn:s,AutoScalingGroups:a,Ec2TagFilters:o?.map((b)=>({Key:b.key,Value:b.value,Type:b.type})),DeploymentConfigName:c,AutoRollbackConfiguration:l?{Enabled:l.enabled,Events:l.events}:void 0,AlarmConfiguration:u?{Enabled:u.enabled,Alarms:u.alarms?.map((b)=>({Name:b.name})),IgnorePollAlarmFailure:u.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:m?{TargetGroupInfoList:m.targetGroupInfoList?.map((b)=>({Name:b.name})),ElbInfoList:m.elbInfoList?.map((b)=>({Name:b.name}))}:void 0,BlueGreenDeploymentConfiguration:p?{TerminateBlueInstancesOnDeploymentSuccess:p.terminateBlueInstancesOnDeploymentSuccess?{Action:p.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:p.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:p.deploymentReadyOption?{ActionOnTimeout:p.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:p.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:p.greenFleetProvisioningOption?{Action:p.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:r}]}},logicalId:y}}static createDeploymentConfig(e){let{slug:t,environment:n,deploymentConfigName:r,minimumHealthyHosts:i,trafficRoutingConfig:s}=e,a=r||S({slug:t,environment:n,resourceType:"deploy-config"}),o=f(a);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:a,MinimumHealthyHosts:i?{Type:i.type,Value:i.value}:void 0,TrafficRoutingConfig:s?{Type:s.type,TimeBasedCanary:s.timeBasedCanary?{CanaryPercentage:s.timeBasedCanary.canaryPercentage,CanaryInterval:s.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:s.timeBasedLinear?{LinearPercentage:s.timeBasedLinear.linearPercentage,LinearInterval:s.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:o}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(e,t)=>({type:e,value:t})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,t)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:t}}),linear:(e,t)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:t}})};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:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:e},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withManualApproval:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"STOP_DEPLOYMENT",waitTimeInMinutes:e},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:(e,t,n,r)=>{let{application:i,logicalId:s}=Z.createApplication({slug:e,environment:t,computePlatform:"Server"}),{deploymentGroup:a,logicalId:o}=Z.createDeploymentGroup(s,{slug:e,environment:t,serviceRoleArn:n,autoScalingGroups:r,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:Z.RollbackConfigs.onFailure()});return{application:i,appId:s,deploymentGroup:a,groupId:o}},lambdaCanaryDeployment:(e,t,n,r=10,i=5)=>{let{application:s,logicalId:a}=Z.createApplication({slug:e,environment:t,computePlatform:"Lambda"}),{deploymentConfig:o,logicalId:c}=Z.createDeploymentConfig({slug:e,environment:t,trafficRoutingConfig:Z.TrafficRouting.canary(r,i)}),{deploymentGroup:l,logicalId:u}=Z.createDeploymentGroup(a,{slug:e,environment:t,serviceRoleArn:n,deploymentConfigName:C.Ref(c),autoRollbackConfiguration:Z.RollbackConfigs.onAlarmOrFailure()});return{application:s,appId:a,deploymentConfig:o,configId:c,deploymentGroup:l,groupId:u}},ecsBlueGreenDeployment:(e,t,n,r)=>{let{application:i,logicalId:s}=Z.createApplication({slug:e,environment:t,computePlatform:"ECS"}),{deploymentGroup:a,logicalId:o}=Z.createDeploymentGroup(s,{slug:e,environment:t,serviceRoleArn:n,loadBalancerInfo:{targetGroupInfoList:[{name:r}]},blueGreenDeploymentConfiguration:Z.BlueGreenConfigs.standard(),autoRollbackConfiguration:Z.RollbackConfigs.onFailure()});return{application:i,appId:s,deploymentGroup:a,groupId:o}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,t=5)=>({type:"canary",canaryPercentage:e,canaryInterval:t}),allAtOnce:()=>({type:"all-at-once"})}}class H{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(e,t="md5"){let n=bt(e);return Da(t).update(n).digest("hex")}static computeShortHash(e){return H.computeFileHash(e).slice(0,8)}static getContentType(e){let t=br(e).toLowerCase();return H.ContentTypes[t]||"application/octet-stream"}static shouldHashFile(e,t){return![...H.NoHashPatterns,...t||[]].some((r)=>r.test(e))}static generateHashedFilename(e,t){let n=br(e),r=Ma(e,n),i=hr(e);if(i===".")return`${r}.${t}${n}`;return et(i,`${r}.${t}${n}`)}static collectFiles(e,t){let n=[],r=t||e;if(!Qt(e))return n;let i=xa(e,{withFileTypes:!0});for(let s of i){let a=et(e,s.name);if(s.isDirectory())n.push(...H.collectFiles(a,r));else if(s.isFile())n.push(a)}return n}static hashDirectory(e){let{sourceDir:t,outputDir:n,excludePatterns:r=[],hashAlgorithm:i="md5",copyUnhashed:s=!0}=e,a=H.collectFiles(t),o=[],c={};for(let u of a){let m=u.replace(t,"").replace(/^[/\\]/,""),p=H.shouldHashFile(m,r),g=ka(u),y=p?H.computeFileHash(u,i).slice(0,8):"",h=p?H.generateHashedFilename(m,y):m,b={originalPath:m,hashedPath:h,hash:y,size:g.size,contentType:H.getContentType(u)};if(o.push(b),c[m]=h,n){let v=et(n,h),T=hr(v);if(!Qt(T)){let{mkdirSync:A}=Fs("node:fs");A(T,{recursive:!0})}if(p||s)Na(u,v)}}let l={version:"1.0",timestamp:new Date().toISOString(),assets:o,hashMap:c};if(n){let u=et(n,"asset-manifest.json");St(u,JSON.stringify(l,null,2))}return l}static getInvalidationPaths(e,t){let n=[];if(!e)return["/*"];let r=e.hashMap,i=t.hashMap;for(let[s,a]of Object.entries(i)){let o=r[s];if(!o||o!==a){if(n.push(`/${s}`),o&&o!==a)n.push(`/${o}`)}}for(let[s,a]of Object.entries(r))if(!i[s])n.push(`/${s}`),n.push(`/${a}`);if(n.length>100)return["/*"];return[...new Set(n)]}static updateHtmlReferences(e){let{htmlDir:t,manifest:n,basePath:r=""}=e,i=H.collectFiles(t).filter((s)=>s.endsWith(".html")||s.endsWith(".htm"));for(let s of i){let a=bt(s,"utf-8");for(let[o,c]of Object.entries(n.hashMap)){if(o===c)continue;let l=[new RegExp(`(src|href)=["']${r}/?${H.escapeRegExp(o)}["']`,"g"),new RegExp(`url\\(["']?${r}/?${H.escapeRegExp(o)}["']?\\)`,"g")];for(let u of l)a=a.replace(u,(m)=>m.replace(o,c))}St(s,a)}}static updateCssReferences(e){let{cssDir:t,manifest:n,basePath:r=""}=e,i=H.collectFiles(t).filter((s)=>s.endsWith(".css"));for(let s of i){let a=bt(s,"utf-8");for(let[o,c]of Object.entries(n.hashMap)){if(o===c)continue;let l=new RegExp(`url\\(["']?${r}/?${H.escapeRegExp(o)}["']?\\)`,"g");a=a.replace(l,`url(${r}/${c})`)}St(s,a)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:t,keyPrefix:n="",excludePatterns:r=[],cacheControl:i={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return H.hashDirectory({sourceDir:t,excludePatterns:r}).assets.map((a)=>{let o=a.hash!=="",c=a.contentType==="text/html",l=i.unhashed||"public, max-age=3600";if(c)l=i.html||"public, max-age=0, must-revalidate";else if(o)l=i.hashed||"public, max-age=31536000, immutable";return{localPath:et(t,a.originalPath),s3Key:n?`${n}/${a.hashedPath}`:a.hashedPath,contentType:a.contentType,cacheControl:l,hash:a.hash}})}static compareManifests(e,t){let n={added:[],removed:[],changed:[],unchanged:[]},r=new Set(Object.keys(e.hashMap)),i=new Set(Object.keys(t.hashMap));for(let s of i)if(!r.has(s))n.added.push(s);for(let s of r)if(!i.has(s))n.removed.push(s);for(let s of i)if(r.has(s))if(e.hashMap[s]!==t.hashMap[s])n.changed.push(s);else n.unchanged.push(s);return n}static loadManifest(e){if(!Qt(e))return null;try{let t=bt(e,"utf-8");return JSON.parse(t)}catch{return null}}static saveManifest(e,t){St(t,JSON.stringify(e,null,2))}}class tt{static createSecret(e){let{slug:t,environment:n,secretName:r,description:i,secretString:s,kmsKeyId:a,tags:o}=e,c=r||S({slug:t,environment:n,resourceType:"secret"}),l=f(c),u={Type:"AWS::SecretsManager::Secret",Properties:{Name:c,Description:i,SecretString:s,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:n},...o?Object.entries(o).map(([m,p])=>({Key:m,Value:p})):[]]}};if(a)u.Properties.KmsKeyId=a;return{secret:u,logicalId:l}}static createGeneratedSecret(e){let{slug:t,environment:n,secretName:r,description:i,excludeCharacters:s,excludeLowercase:a,excludeNumbers:o,excludePunctuation:c,excludeUppercase:l,passwordLength:u,requireEachIncludedType:m,kmsKeyId:p,tags:g}=e,y=r||S({slug:t,environment:n,resourceType:"secret"}),h=f(y),b={Type:"AWS::SecretsManager::Secret",Properties:{Name:y,Description:i,GenerateSecretString:{ExcludeCharacters:s,ExcludeLowercase:a,ExcludeNumbers:o,ExcludePunctuation:c,ExcludeUppercase:l,PasswordLength:u||32,RequireEachIncludedType:m!==!1},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:n},...g?Object.entries(g).map(([v,T])=>({Key:v,Value:T})):[]]}};if(p)b.Properties.KmsKeyId=p;return{secret:b,logicalId:h}}static createDatabaseSecret(e){let{slug:t,environment:n,secretName:r,username:i,dbname:s,engine:a,host:o,port:c,kmsKeyId:l}=e,u=r||S({slug:t,environment:n,resourceType:"db-secret"}),m=f(u),p={username:i};if(s)p.dbname=s;if(a)p.engine=a;if(o)p.host=o;if(c)p.port=c;let g={Type:"AWS::SecretsManager::Secret",Properties:{Name:u,Description:`Database credentials for ${i}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(p),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n},{Key:"Type",Value:"database"}]}};if(l)g.Properties.KmsKeyId=l;return{secret:g,logicalId:m}}static attachToDatabase(e){let{slug:t,environment:n,secretId:r,targetId:i,targetType:s}=e,a=S({slug:t,environment:n,resourceType:"secret-attachment"}),o=f(a);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:r,TargetId:i,TargetType:s}},logicalId:o}}static enableRotation(e){let{slug:t,environment:n,secretId:r,rotationLambdaArn:i,automaticallyAfterDays:s,rotationType:a,kmsKeyArn:o,vpcSecurityGroupIds:c,vpcSubnetIds:l}=e,u=S({slug:t,environment:n,resourceType:"secret-rotation"}),m=f(u),p={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:r,RotationRules:{AutomaticallyAfterDays:s||30}}};if(i)p.Properties.RotationLambdaARN=i;else if(a)p.Properties.HostedRotationLambda={RotationType:a,KmsKeyArn:o,VpcSecurityGroupIds:c,VpcSubnetIds:l};return{rotation:p,logicalId:m}}static SecretTypes={apiKey:(e,t,n)=>tt.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-${n}-api-key`,description:`API key for ${n}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,t,n)=>tt.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-${n}-oauth-secret`,description:`OAuth client secret for ${n}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,t)=>tt.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,t)=>tt.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-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 _{static createParameter(e){let{slug:t,environment:n,parameterName:r,value:i,type:s="String",description:a,tier:o="Standard",tags:c}=e,l=r||S({slug:t,environment:n,resourceType:"parameter"}),u=f(l);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${t}/${n}/${l}`,Type:s,Value:i,Description:a,Tier:o,Tags:{Name:l,Environment:n,...c}}},logicalId:u}}static createString(e,t,n,r,i){return _.createParameter({slug:e,environment:t,parameterName:n,value:r,type:"String",description:i})}static createSecureString(e,t,n,r,i){return _.createParameter({slug:e,environment:t,parameterName:n,value:r,type:"SecureString",description:i})}static createStringList(e,t,n,r,i){return _.createParameter({slug:e,environment:t,parameterName:n,value:r.join(","),type:"StringList",description:i})}static Parameters={databaseUrl:(e,t,n)=>_.createSecureString(e,t,"database-url",n,"Database connection URL"),apiEndpoint:(e,t,n)=>_.createString(e,t,"api-endpoint",n,"API endpoint URL"),appVersion:(e,t,n)=>_.createString(e,t,"app-version",n,"Application version"),featureFlags:(e,t,n)=>_.createStringList(e,t,"feature-flags",n,"Enabled feature flags"),apiKey:(e,t,n,r)=>_.createSecureString(e,t,`${n}-api-key`,r,`API key for ${n}`),oauthCredentials:(e,t,n,r)=>{let i=_.createString(e,t,"oauth-client-id",n,"OAuth client ID"),s=_.createSecureString(e,t,"oauth-client-secret",r,"OAuth client secret");return{clientId:i,clientSecret:s}},smtpCredentials:(e,t,n,r,i,s)=>{let a=_.createString(e,t,"smtp-username",n,"SMTP username"),o=_.createSecureString(e,t,"smtp-password",r,"SMTP password"),c=_.createString(e,t,"smtp-host",i,"SMTP host"),l=_.createString(e,t,"smtp-port",s.toString(),"SMTP port");return{username:a,password:o,host:c,port:l}},redisUrl:(e,t,n)=>_.createSecureString(e,t,"redis-url",n,"Redis connection URL"),s3Bucket:(e,t,n)=>_.createString(e,t,"s3-bucket",n,"S3 bucket name"),cloudFrontDistribution:(e,t,n)=>_.createString(e,t,"cloudfront-distribution-id",n,"CloudFront distribution ID")}}class nt{static createDomain(e){let{slug:t,environment:n,domainName:r,engineVersion:i="OpenSearch_2.11",instanceType:s="t3.small.search",instanceCount:a=1,volumeSize:o=10,volumeType:c="gp3",dedicatedMaster:l=!1,dedicatedMasterType:u,dedicatedMasterCount:m=3,multiAz:p=!1,availabilityZoneCount:g=2,vpc:y,encryption:h,enforceHttps:b=!0,tlsSecurityPolicy:v="Policy-Min-TLS-1-2-2019-07",advancedSecurity:T,autoSnapshotHour:A=0,autoTune:R=!0,tags:P={}}=e,E=r||S({slug:t,environment:n,resourceType:"search"}),w=f(E);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:E,EngineVersion:i,ClusterConfig:{InstanceType:s,InstanceCount:a,DedicatedMasterEnabled:l,...l&&{DedicatedMasterType:u||s,DedicatedMasterCount:m},ZoneAwarenessEnabled:p,...p&&{ZoneAwarenessConfig:{AvailabilityZoneCount:g}}},EBSOptions:{EBSEnabled:!0,VolumeType:c,VolumeSize:o},DomainEndpointOptions:{EnforceHTTPS:b,TLSSecurityPolicy:v},SnapshotOptions:{AutomatedSnapshotStartHour:A},...y&&{VPCOptions:{SubnetIds:y.subnetIds,SecurityGroupIds:y.securityGroupIds}},...h&&{EncryptionAtRestOptions:{Enabled:h.atRest??!0,...h.kmsKeyId&&{KmsKeyId:h.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:h.nodeToNode??!0}},...T&&{AdvancedSecurityOptions:{Enabled:T.enabled,InternalUserDatabaseEnabled:T.internalUserDatabase??!0,...T.masterUserName&&T.masterUserPassword&&{MasterUserOptions:{MasterUserName:T.masterUserName,MasterUserPassword:T.masterUserPassword}},...T.masterUserArn&&{MasterUserOptions:{MasterUserARN:T.masterUserArn}}}},...R&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:n},...Object.entries(P).map(([D,k])=>({Key:D,Value:k}))]}},logicalId:w}}static createAccessPolicy(e,t){let{ipAddresses:n,iamPrincipalArns:r,allowAll:i,vpcEndpoint:s}=t;if(i)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let a=[];if(r&&r.length>0)a.push({Effect:"Allow",Principal:{AWS:r},Action:"es:*",Resource:e});if(n&&n.length>0)a.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e,Condition:{IpAddress:{"aws:SourceIp":n}}});if(s)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};return{Version:"2012-10-17",Statement:a}}static DomainPresets={development:(e,t)=>nt.createDomain({slug:e,environment:t,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,t,n)=>nt.createDomain({slug:e,environment:t,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:n,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(e,t)=>nt.createDomain({slug:e,environment:t,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,t,n)=>nt.createDomain({slug:e,environment:t,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:n,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(e){let{slug:t,environment:n,sourceDomain:r,targetDomain:i,protocol:s="https"}=e,a=S({slug:t,environment:n,resourceType:"s3",suffix:"redirect"}),o=f(a),c=f(`${a}-policy`),l={Type:"AWS::S3::Bucket",Properties:{BucketName:r,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:i,Protocol:s}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:n},{Key:"Purpose",Value:"Domain Redirect"}]}},u={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:C.Ref(o),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[C.Join("",[C.GetAtt(o,"Arn"),"/*"])]}]}}};return{bucket:l,bucketPolicy:u,logicalId:o,policyLogicalId:c}}static createPathRedirectFunction(e){let{slug:t,environment:n,rules:r}=e,i=S({slug:t,environment:n,resourceType:"cf-redirect"}),s=f(i),a=At.generateRedirectFunctionCode(r);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:i,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${t} (${n})`,Runtime:"cloudfront-js-2.0"},FunctionCode:a}},logicalId:s,functionCode:a}}static generateRedirectFunctionCode(e){return`function handler(event) {
2293
+ | limit 50`,region:r,title:"Recent Errors and Warnings"}}),a+=6;return fr.createDashboard({slug:t,environment:n,widgets:s})}static DashboardTemplates={staticWebsite:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.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",e.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",e.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",e.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",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:e.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",e.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:e.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",e.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",e.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",e.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",e.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",e.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...e.lambdaFunctionNames.map((t,n)=>({type:"metric",x:n%3*8,y:7+Math.floor(n/3)*6,width:8,height:6,properties:{title:`${t} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",t],["AWS/Lambda","Duration","FunctionName",t],["AWS/Lambda","Errors","FunctionName",t]],period:300,stat:"Sum"}}))]}),containerService:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Container Service Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"ECS CPU",region:e.region||"us-east-1",metrics:[["AWS/ECS","CPUUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"ECS Memory",region:e.region||"us-east-1",metrics:[["AWS/ECS","MemoryUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Running Tasks",region:e.region||"us-east-1",metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:0,y:7,width:8,height:6,properties:{title:"ALB Requests",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",e.albName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:7,width:8,height:6,properties:{title:"Response Time",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",e.albName]],period:60,stat:"Average"}},{type:"metric",x:16,y:7,width:8,height:6,properties:{title:"Healthy Hosts",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","HealthyHostCount","LoadBalancer",e.albName]],period:60,stat:"Average"}},...e.rdsInstanceId?[{type:"metric",x:0,y:13,width:12,height:6,properties:{title:"RDS CPU",region:e.region||"us-east-1",metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",e.rdsInstanceId]],period:300,stat:"Average"}},{type:"metric",x:12,y:13,width:12,height:6,properties:{title:"RDS Connections",region:e.region||"us-east-1",metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",e.rdsInstanceId]],period:60,stat:"Sum"}}]:[]]})};static Config={createAlarmConfig:(e)=>{let{metricName:t,namespace:n,threshold:r,comparisonOperator:i="GreaterThanThreshold",evaluationPeriods:s=1,period:a=300,statistic:o="Average",treatMissingData:c="missing"}=e;return{MetricName:t,Namespace:n,Threshold:r,ComparisonOperator:i,EvaluationPeriods:s,Period:a,Statistic:o,TreatMissingData:c}},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:(e=80)=>({metricName:"CPUUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(e=80)=>({metricName:"MemoryUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(e=10)=>({metricName:"Errors",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(e=5000)=>({metricName:"Duration",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(e=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(e=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(e=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class Z{static createUserPool(e){let{slug:t,environment:n,userPoolName:r,aliasAttributes:i,autoVerifiedAttributes:s,passwordPolicy:a,mfaConfiguration:o,emailConfiguration:c,smsConfiguration:l,lambdaTriggers:u,userPoolAddOns:m,accountRecoverySetting:p}=e,g=r||S({slug:t,environment:n,resourceType:"user-pool"}),y=f(g),h={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:g,Policies:a?{PasswordPolicy:{MinimumLength:a.minimumLength,RequireLowercase:a.requireLowercase,RequireUppercase:a.requireUppercase,RequireNumbers:a.requireNumbers,RequireSymbols:a.requireSymbols,TemporaryPasswordValidityDays:a.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:o,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(i&&i.length>0)h.Properties.UsernameAttributes=i;if(s&&s.length>0)h.Properties.AutoVerifiedAttributes=s;if(c)h.Properties.EmailConfiguration={EmailSendingAccount:c.emailSendingAccount,From:c.from,ReplyToEmailAddress:c.replyToEmailAddress,SourceArn:c.sourceArn,ConfigurationSet:c.configurationSet};if(l)h.Properties.SmsConfiguration={ExternalId:l.externalId,SnsCallerArn:l.snsCallerArn};if(u)h.Properties.LambdaConfig={PreSignUp:u.preSignUp,PostConfirmation:u.postConfirmation,PreAuthentication:u.preAuthentication,PostAuthentication:u.postAuthentication,CustomMessage:u.customMessage,DefineAuthChallenge:u.defineAuthChallenge,CreateAuthChallenge:u.createAuthChallenge,VerifyAuthChallengeResponse:u.verifyAuthChallengeResponse,PreTokenGeneration:u.preTokenGeneration,UserMigration:u.userMigration};if(m)h.Properties.UserPoolAddOns={AdvancedSecurityMode:m.advancedSecurityMode};if(p)h.Properties.AccountRecoverySetting={RecoveryMechanisms:p.recoveryMechanisms};return{userPool:h,logicalId:y}}static createUserPoolClient(e,t){let{slug:n,environment:r,clientName:i,generateSecret:s=!1,refreshTokenValidity:a,accessTokenValidity:o,idTokenValidity:c,tokenValidityUnits:l,readAttributes:u,writeAttributes:m,explicitAuthFlows:p,preventUserExistenceErrors:g,enableTokenRevocation:y,callbackURLs:h,logoutURLs:b,allowedOAuthFlows:C,allowedOAuthScopes:T,allowedOAuthFlowsUserPoolClient:A,supportedIdentityProviders:R}=t,P=i||S({slug:n,environment:r,resourceType:"user-pool-client"}),E=f(P);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:P,UserPoolId:v.Ref(e),GenerateSecret:s,RefreshTokenValidity:a,AccessTokenValidity:o,IdTokenValidity:c,TokenValidityUnits:l,ReadAttributes:u,WriteAttributes:m,ExplicitAuthFlows:p,PreventUserExistenceErrors:g,EnableTokenRevocation:y,CallbackURLs:h,LogoutURLs:b,AllowedOAuthFlows:C,AllowedOAuthScopes:T,AllowedOAuthFlowsUserPoolClient:A,SupportedIdentityProviders:R}},logicalId:E}}static createUserPoolDomain(e,t){let{slug:n,environment:r,domain:i,customDomainConfig:s}=t,a=S({slug:n,environment:r,resourceType:"user-pool-domain"}),o=f(a);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:i,UserPoolId:v.Ref(e),CustomDomainConfig:s}},logicalId:o}}static createIdentityPool(e){let{slug:t,environment:n,identityPoolName:r,allowUnauthenticatedIdentities:i=!1,cognitoIdentityProviders:s,supportedLoginProviders:a,samlProviderARNs:o,openIdConnectProviderARNs:c}=e,l=r||S({slug:t,environment:n,resourceType:"identity-pool"}),u=f(l);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:l,AllowUnauthenticatedIdentities:i,CognitoIdentityProviders:s,SupportedLoginProviders:a,SamlProviderARNs:o,OpenIdConnectProviderARNs:c}},logicalId:u}}static createIdentityPoolRoleAttachment(e,t){let{slug:n,environment:r,authenticatedRole:i,unauthenticatedRole:s,roleMappings:a}=t,o=S({slug:n,environment:r,resourceType:"identity-pool-role-attachment"}),c=f(o),l={authenticated:i};if(s)l.unauthenticated=s;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:v.Ref(e),Roles:l,RoleMappings:a}},logicalId:c}}static createAuthenticatedRole(e){let{slug:t,environment:n,identityPoolLogicalId:r}=e,i=S({slug:t,environment:n,resourceType:"cognito-authenticated-role"}),s=f(i);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:i,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":v.Ref(r)},"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:i},{Key:"Environment",Value:n}]}},logicalId:s}}static createUnauthenticatedRole(e){let{slug:t,environment:n,identityPoolLogicalId:r}=e,i=S({slug:t,environment:n,resourceType:"cognito-unauthenticated-role"}),s=f(i);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:i,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":v.Ref(r)},"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:i},{Key:"Environment",Value:n}]}},logicalId:s}}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:(e,t,n)=>{let{userPool:r,logicalId:i}=Z.createUserPool({slug:e,environment:t,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Z.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:s,logicalId:a}=Z.createUserPoolClient(i,{slug:e,environment:t,explicitAuthFlows:[...Z.AuthFlows.standard],callbackURLs:[n],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Z.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:r,poolId:i,client:s,clientId:a}},mobileApp:(e,t)=>{let{userPool:n,logicalId:r}=Z.createUserPool({slug:e,environment:t,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Z.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:i,logicalId:s}=Z.createUserPoolClient(r,{slug:e,environment:t,explicitAuthFlows:[...Z.AuthFlows.standard]}),{identityPool:a,logicalId:o}=Z.createIdentityPool({slug:e,environment:t,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:v.Ref(s),ProviderName:v.GetAtt(r,"ProviderName")}]}),{role:c,logicalId:l}=Z.createAuthenticatedRole({slug:e,environment:t,identityPoolLogicalId:o}),{attachment:u,logicalId:m}=Z.createIdentityPoolRoleAttachment(o,{slug:e,environment:t,authenticatedRole:v.GetAtt(l,"Arn")});return{userPool:n,poolId:r,client:i,clientId:s,identityPool:a,identityPoolId:o,authRole:c,authRoleId:l,attachment:u,attachmentId:m}}}}import{createHash as Da}from"node:crypto";import{copyFileSync as Na,existsSync as Qt,readdirSync as xa,readFileSync as St,statSync as ka,writeFileSync as At}from"node:fs";import{basename as Ma,dirname as hr,extname as br,join as tt}from"node:path";class X{static createApplication(e){let{slug:t,environment:n,applicationName:r,computePlatform:i}=e,s=r||S({slug:t,environment:n,resourceType:"deploy-app"}),a=f(s);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:s,ComputePlatform:i,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:n}]}},logicalId:a}}static createDeploymentGroup(e,t){let{slug:n,environment:r,deploymentGroupName:i,serviceRoleArn:s,autoScalingGroups:a,ec2TagFilters:o,deploymentConfigName:c,autoRollbackConfiguration:l,alarmConfiguration:u,loadBalancerInfo:m,blueGreenDeploymentConfiguration:p}=t,g=i||S({slug:n,environment:r,resourceType:"deploy-group"}),y=f(g);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:v.Ref(e),DeploymentGroupName:g,ServiceRoleArn:s,AutoScalingGroups:a,Ec2TagFilters:o?.map((b)=>({Key:b.key,Value:b.value,Type:b.type})),DeploymentConfigName:c,AutoRollbackConfiguration:l?{Enabled:l.enabled,Events:l.events}:void 0,AlarmConfiguration:u?{Enabled:u.enabled,Alarms:u.alarms?.map((b)=>({Name:b.name})),IgnorePollAlarmFailure:u.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:m?{TargetGroupInfoList:m.targetGroupInfoList?.map((b)=>({Name:b.name})),ElbInfoList:m.elbInfoList?.map((b)=>({Name:b.name}))}:void 0,BlueGreenDeploymentConfiguration:p?{TerminateBlueInstancesOnDeploymentSuccess:p.terminateBlueInstancesOnDeploymentSuccess?{Action:p.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:p.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:p.deploymentReadyOption?{ActionOnTimeout:p.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:p.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:p.greenFleetProvisioningOption?{Action:p.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:r}]}},logicalId:y}}static createDeploymentConfig(e){let{slug:t,environment:n,deploymentConfigName:r,minimumHealthyHosts:i,trafficRoutingConfig:s}=e,a=r||S({slug:t,environment:n,resourceType:"deploy-config"}),o=f(a);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:a,MinimumHealthyHosts:i?{Type:i.type,Value:i.value}:void 0,TrafficRoutingConfig:s?{Type:s.type,TimeBasedCanary:s.timeBasedCanary?{CanaryPercentage:s.timeBasedCanary.canaryPercentage,CanaryInterval:s.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:s.timeBasedLinear?{LinearPercentage:s.timeBasedLinear.linearPercentage,LinearInterval:s.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:o}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(e,t)=>({type:e,value:t})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,t)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:t}}),linear:(e,t)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:t}})};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:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:e},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withManualApproval:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"STOP_DEPLOYMENT",waitTimeInMinutes:e},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:(e,t,n,r)=>{let{application:i,logicalId:s}=X.createApplication({slug:e,environment:t,computePlatform:"Server"}),{deploymentGroup:a,logicalId:o}=X.createDeploymentGroup(s,{slug:e,environment:t,serviceRoleArn:n,autoScalingGroups:r,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:X.RollbackConfigs.onFailure()});return{application:i,appId:s,deploymentGroup:a,groupId:o}},lambdaCanaryDeployment:(e,t,n,r=10,i=5)=>{let{application:s,logicalId:a}=X.createApplication({slug:e,environment:t,computePlatform:"Lambda"}),{deploymentConfig:o,logicalId:c}=X.createDeploymentConfig({slug:e,environment:t,trafficRoutingConfig:X.TrafficRouting.canary(r,i)}),{deploymentGroup:l,logicalId:u}=X.createDeploymentGroup(a,{slug:e,environment:t,serviceRoleArn:n,deploymentConfigName:v.Ref(c),autoRollbackConfiguration:X.RollbackConfigs.onAlarmOrFailure()});return{application:s,appId:a,deploymentConfig:o,configId:c,deploymentGroup:l,groupId:u}},ecsBlueGreenDeployment:(e,t,n,r)=>{let{application:i,logicalId:s}=X.createApplication({slug:e,environment:t,computePlatform:"ECS"}),{deploymentGroup:a,logicalId:o}=X.createDeploymentGroup(s,{slug:e,environment:t,serviceRoleArn:n,loadBalancerInfo:{targetGroupInfoList:[{name:r}]},blueGreenDeploymentConfiguration:X.BlueGreenConfigs.standard(),autoRollbackConfiguration:X.RollbackConfigs.onFailure()});return{application:i,appId:s,deploymentGroup:a,groupId:o}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,t=5)=>({type:"canary",canaryPercentage:e,canaryInterval:t}),allAtOnce:()=>({type:"all-at-once"})}}class j{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(e,t="md5"){let n=St(e);return Da(t).update(n).digest("hex")}static computeShortHash(e){return j.computeFileHash(e).slice(0,8)}static getContentType(e){let t=br(e).toLowerCase();return j.ContentTypes[t]||"application/octet-stream"}static shouldHashFile(e,t){return![...j.NoHashPatterns,...t||[]].some((r)=>r.test(e))}static generateHashedFilename(e,t){let n=br(e),r=Ma(e,n),i=hr(e);if(i===".")return`${r}.${t}${n}`;return tt(i,`${r}.${t}${n}`)}static collectFiles(e,t){let n=[],r=t||e;if(!Qt(e))return n;let i=xa(e,{withFileTypes:!0});for(let s of i){let a=tt(e,s.name);if(s.isDirectory())n.push(...j.collectFiles(a,r));else if(s.isFile())n.push(a)}return n}static hashDirectory(e){let{sourceDir:t,outputDir:n,excludePatterns:r=[],hashAlgorithm:i="md5",copyUnhashed:s=!0}=e,a=j.collectFiles(t),o=[],c={};for(let u of a){let m=u.replace(t,"").replace(/^[/\\]/,""),p=j.shouldHashFile(m,r),g=ka(u),y=p?j.computeFileHash(u,i).slice(0,8):"",h=p?j.generateHashedFilename(m,y):m,b={originalPath:m,hashedPath:h,hash:y,size:g.size,contentType:j.getContentType(u)};if(o.push(b),c[m]=h,n){let C=tt(n,h),T=hr(C);if(!Qt(T)){let{mkdirSync:A}=Fs("node:fs");A(T,{recursive:!0})}if(p||s)Na(u,C)}}let l={version:"1.0",timestamp:new Date().toISOString(),assets:o,hashMap:c};if(n){let u=tt(n,"asset-manifest.json");At(u,JSON.stringify(l,null,2))}return l}static getInvalidationPaths(e,t){let n=[];if(!e)return["/*"];let r=e.hashMap,i=t.hashMap;for(let[s,a]of Object.entries(i)){let o=r[s];if(!o||o!==a){if(n.push(`/${s}`),o&&o!==a)n.push(`/${o}`)}}for(let[s,a]of Object.entries(r))if(!i[s])n.push(`/${s}`),n.push(`/${a}`);if(n.length>100)return["/*"];return[...new Set(n)]}static updateHtmlReferences(e){let{htmlDir:t,manifest:n,basePath:r=""}=e,i=j.collectFiles(t).filter((s)=>s.endsWith(".html")||s.endsWith(".htm"));for(let s of i){let a=St(s,"utf-8");for(let[o,c]of Object.entries(n.hashMap)){if(o===c)continue;let l=[new RegExp(`(src|href)=["']${r}/?${j.escapeRegExp(o)}["']`,"g"),new RegExp(`url\\(["']?${r}/?${j.escapeRegExp(o)}["']?\\)`,"g")];for(let u of l)a=a.replace(u,(m)=>m.replace(o,c))}At(s,a)}}static updateCssReferences(e){let{cssDir:t,manifest:n,basePath:r=""}=e,i=j.collectFiles(t).filter((s)=>s.endsWith(".css"));for(let s of i){let a=St(s,"utf-8");for(let[o,c]of Object.entries(n.hashMap)){if(o===c)continue;let l=new RegExp(`url\\(["']?${r}/?${j.escapeRegExp(o)}["']?\\)`,"g");a=a.replace(l,`url(${r}/${c})`)}At(s,a)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:t,keyPrefix:n="",excludePatterns:r=[],cacheControl:i={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return j.hashDirectory({sourceDir:t,excludePatterns:r}).assets.map((a)=>{let o=a.hash!=="",c=a.contentType==="text/html",l=i.unhashed||"public, max-age=3600";if(c)l=i.html||"public, max-age=0, must-revalidate";else if(o)l=i.hashed||"public, max-age=31536000, immutable";return{localPath:tt(t,a.originalPath),s3Key:n?`${n}/${a.hashedPath}`:a.hashedPath,contentType:a.contentType,cacheControl:l,hash:a.hash}})}static compareManifests(e,t){let n={added:[],removed:[],changed:[],unchanged:[]},r=new Set(Object.keys(e.hashMap)),i=new Set(Object.keys(t.hashMap));for(let s of i)if(!r.has(s))n.added.push(s);for(let s of r)if(!i.has(s))n.removed.push(s);for(let s of i)if(r.has(s))if(e.hashMap[s]!==t.hashMap[s])n.changed.push(s);else n.unchanged.push(s);return n}static loadManifest(e){if(!Qt(e))return null;try{let t=St(e,"utf-8");return JSON.parse(t)}catch{return null}}static saveManifest(e,t){At(t,JSON.stringify(e,null,2))}}class nt{static createSecret(e){let{slug:t,environment:n,secretName:r,description:i,secretString:s,kmsKeyId:a,tags:o}=e,c=r||S({slug:t,environment:n,resourceType:"secret"}),l=f(c),u={Type:"AWS::SecretsManager::Secret",Properties:{Name:c,Description:i,SecretString:s,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:n},...o?Object.entries(o).map(([m,p])=>({Key:m,Value:p})):[]]}};if(a)u.Properties.KmsKeyId=a;return{secret:u,logicalId:l}}static createGeneratedSecret(e){let{slug:t,environment:n,secretName:r,description:i,excludeCharacters:s,excludeLowercase:a,excludeNumbers:o,excludePunctuation:c,excludeUppercase:l,passwordLength:u,requireEachIncludedType:m,kmsKeyId:p,tags:g}=e,y=r||S({slug:t,environment:n,resourceType:"secret"}),h=f(y),b={Type:"AWS::SecretsManager::Secret",Properties:{Name:y,Description:i,GenerateSecretString:{ExcludeCharacters:s,ExcludeLowercase:a,ExcludeNumbers:o,ExcludePunctuation:c,ExcludeUppercase:l,PasswordLength:u||32,RequireEachIncludedType:m!==!1},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:n},...g?Object.entries(g).map(([C,T])=>({Key:C,Value:T})):[]]}};if(p)b.Properties.KmsKeyId=p;return{secret:b,logicalId:h}}static createDatabaseSecret(e){let{slug:t,environment:n,secretName:r,username:i,dbname:s,engine:a,host:o,port:c,kmsKeyId:l}=e,u=r||S({slug:t,environment:n,resourceType:"db-secret"}),m=f(u),p={username:i};if(s)p.dbname=s;if(a)p.engine=a;if(o)p.host=o;if(c)p.port=c;let g={Type:"AWS::SecretsManager::Secret",Properties:{Name:u,Description:`Database credentials for ${i}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(p),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n},{Key:"Type",Value:"database"}]}};if(l)g.Properties.KmsKeyId=l;return{secret:g,logicalId:m}}static attachToDatabase(e){let{slug:t,environment:n,secretId:r,targetId:i,targetType:s}=e,a=S({slug:t,environment:n,resourceType:"secret-attachment"}),o=f(a);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:r,TargetId:i,TargetType:s}},logicalId:o}}static enableRotation(e){let{slug:t,environment:n,secretId:r,rotationLambdaArn:i,automaticallyAfterDays:s,rotationType:a,kmsKeyArn:o,vpcSecurityGroupIds:c,vpcSubnetIds:l}=e,u=S({slug:t,environment:n,resourceType:"secret-rotation"}),m=f(u),p={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:r,RotationRules:{AutomaticallyAfterDays:s||30}}};if(i)p.Properties.RotationLambdaARN=i;else if(a)p.Properties.HostedRotationLambda={RotationType:a,KmsKeyArn:o,VpcSecurityGroupIds:c,VpcSubnetIds:l};return{rotation:p,logicalId:m}}static SecretTypes={apiKey:(e,t,n)=>nt.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-${n}-api-key`,description:`API key for ${n}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,t,n)=>nt.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-${n}-oauth-secret`,description:`OAuth client secret for ${n}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,t)=>nt.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,t)=>nt.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-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(e){let{slug:t,environment:n,parameterName:r,value:i,type:s="String",description:a,tier:o="Standard",tags:c}=e,l=r||S({slug:t,environment:n,resourceType:"parameter"}),u=f(l);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${t}/${n}/${l}`,Type:s,Value:i,Description:a,Tier:o,Tags:{Name:l,Environment:n,...c}}},logicalId:u}}static createString(e,t,n,r,i){return V.createParameter({slug:e,environment:t,parameterName:n,value:r,type:"String",description:i})}static createSecureString(e,t,n,r,i){return V.createParameter({slug:e,environment:t,parameterName:n,value:r,type:"SecureString",description:i})}static createStringList(e,t,n,r,i){return V.createParameter({slug:e,environment:t,parameterName:n,value:r.join(","),type:"StringList",description:i})}static Parameters={databaseUrl:(e,t,n)=>V.createSecureString(e,t,"database-url",n,"Database connection URL"),apiEndpoint:(e,t,n)=>V.createString(e,t,"api-endpoint",n,"API endpoint URL"),appVersion:(e,t,n)=>V.createString(e,t,"app-version",n,"Application version"),featureFlags:(e,t,n)=>V.createStringList(e,t,"feature-flags",n,"Enabled feature flags"),apiKey:(e,t,n,r)=>V.createSecureString(e,t,`${n}-api-key`,r,`API key for ${n}`),oauthCredentials:(e,t,n,r)=>{let i=V.createString(e,t,"oauth-client-id",n,"OAuth client ID"),s=V.createSecureString(e,t,"oauth-client-secret",r,"OAuth client secret");return{clientId:i,clientSecret:s}},smtpCredentials:(e,t,n,r,i,s)=>{let a=V.createString(e,t,"smtp-username",n,"SMTP username"),o=V.createSecureString(e,t,"smtp-password",r,"SMTP password"),c=V.createString(e,t,"smtp-host",i,"SMTP host"),l=V.createString(e,t,"smtp-port",s.toString(),"SMTP port");return{username:a,password:o,host:c,port:l}},redisUrl:(e,t,n)=>V.createSecureString(e,t,"redis-url",n,"Redis connection URL"),s3Bucket:(e,t,n)=>V.createString(e,t,"s3-bucket",n,"S3 bucket name"),cloudFrontDistribution:(e,t,n)=>V.createString(e,t,"cloudfront-distribution-id",n,"CloudFront distribution ID")}}class rt{static createDomain(e){let{slug:t,environment:n,domainName:r,engineVersion:i="OpenSearch_2.11",instanceType:s="t3.small.search",instanceCount:a=1,volumeSize:o=10,volumeType:c="gp3",dedicatedMaster:l=!1,dedicatedMasterType:u,dedicatedMasterCount:m=3,multiAz:p=!1,availabilityZoneCount:g=2,vpc:y,encryption:h,enforceHttps:b=!0,tlsSecurityPolicy:C="Policy-Min-TLS-1-2-2019-07",advancedSecurity:T,autoSnapshotHour:A=0,autoTune:R=!0,tags:P={}}=e,E=r||S({slug:t,environment:n,resourceType:"search"}),w=f(E);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:E,EngineVersion:i,ClusterConfig:{InstanceType:s,InstanceCount:a,DedicatedMasterEnabled:l,...l&&{DedicatedMasterType:u||s,DedicatedMasterCount:m},ZoneAwarenessEnabled:p,...p&&{ZoneAwarenessConfig:{AvailabilityZoneCount:g}}},EBSOptions:{EBSEnabled:!0,VolumeType:c,VolumeSize:o},DomainEndpointOptions:{EnforceHTTPS:b,TLSSecurityPolicy:C},SnapshotOptions:{AutomatedSnapshotStartHour:A},...y&&{VPCOptions:{SubnetIds:y.subnetIds,SecurityGroupIds:y.securityGroupIds}},...h&&{EncryptionAtRestOptions:{Enabled:h.atRest??!0,...h.kmsKeyId&&{KmsKeyId:h.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:h.nodeToNode??!0}},...T&&{AdvancedSecurityOptions:{Enabled:T.enabled,InternalUserDatabaseEnabled:T.internalUserDatabase??!0,...T.masterUserName&&T.masterUserPassword&&{MasterUserOptions:{MasterUserName:T.masterUserName,MasterUserPassword:T.masterUserPassword}},...T.masterUserArn&&{MasterUserOptions:{MasterUserARN:T.masterUserArn}}}},...R&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:n},...Object.entries(P).map(([D,k])=>({Key:D,Value:k}))]}},logicalId:w}}static createAccessPolicy(e,t){let{ipAddresses:n,iamPrincipalArns:r,allowAll:i,vpcEndpoint:s}=t;if(i)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let a=[];if(r&&r.length>0)a.push({Effect:"Allow",Principal:{AWS:r},Action:"es:*",Resource:e});if(n&&n.length>0)a.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e,Condition:{IpAddress:{"aws:SourceIp":n}}});if(s)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};return{Version:"2012-10-17",Statement:a}}static DomainPresets={development:(e,t)=>rt.createDomain({slug:e,environment:t,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,t,n)=>rt.createDomain({slug:e,environment:t,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:n,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(e,t)=>rt.createDomain({slug:e,environment:t,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,t,n)=>rt.createDomain({slug:e,environment:t,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:n,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 Ct{static createDomainRedirectBucket(e){let{slug:t,environment:n,sourceDomain:r,targetDomain:i,protocol:s="https"}=e,a=S({slug:t,environment:n,resourceType:"s3",suffix:"redirect"}),o=f(a),c=f(`${a}-policy`),l={Type:"AWS::S3::Bucket",Properties:{BucketName:r,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:i,Protocol:s}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:n},{Key:"Purpose",Value:"Domain Redirect"}]}},u={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:v.Ref(o),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[v.Join("",[v.GetAtt(o,"Arn"),"/*"])]}]}}};return{bucket:l,bucketPolicy:u,logicalId:o,policyLogicalId:c}}static createPathRedirectFunction(e){let{slug:t,environment:n,rules:r}=e,i=S({slug:t,environment:n,resourceType:"cf-redirect"}),s=f(i),a=Ct.generateRedirectFunctionCode(r);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:i,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${t} (${n})`,Runtime:"cloudfront-js-2.0"},FunctionCode:a}},logicalId:s,functionCode:a}}static generateRedirectFunctionCode(e){return`function handler(event) {
2294
2294
  const request = event.request;
2295
2295
  const uri = request.uri;
2296
2296
  const querystring = request.querystring;
@@ -2344,7 +2344,7 @@ ${e.map((n)=>{let r=n.preserveQueryString!==!1,i=n.statusCode||301;return` '${n
2344
2344
  }
2345
2345
 
2346
2346
  return request;
2347
- }`}static CommonRedirects={wwwToApex:(e,t="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${e}`,targetDomain:e,protocol:t,preservePath:!0}),apexToWww:(e,t="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:e,targetDomain:`www.${e}`,protocol:t,preservePath:!0}),httpToHttps:(e="/")=>({source:e,target:e,statusCode:301}),addTrailingSlash:(e)=>e.map((t)=>({source:t.endsWith("/")?t.slice(0,-1):t,target:t.endsWith("/")?t:`${t}/`,statusCode:301})),removeTrailingSlash:(e)=>e.map((t)=>({source:t.endsWith("/")&&t!=="/"?t:`${t}/`,target:t.endsWith("/")&&t!=="/"?t.slice(0,-1):t,statusCode:301}))};static Patterns={flattenBlogUrls:(e)=>e.map(({oldPath:t,newPath:n})=>({source:t,target:n,statusCode:301,preserveQueryString:!0})),categoryRename:(e,t)=>[{source:`/${e}`,target:`/${t}`,statusCode:301},{source:`/${e}/`,target:`/${t}/`,statusCode:301}],productSlugChange:(e)=>e.map(({oldSlug:t,newSlug:n})=>({source:`/products/${t}`,target:`/products/${n}`,statusCode:301})),apiVersionRedirect:(e,t,n)=>n.map((r)=>({source:`/api/${e}/${r}`,target:`/api/${t}/${r}`,statusCode:307,preserveQueryString:!0})),gonePages:(e)=>e.map((t)=>({source:t,target:"/410",statusCode:301}))};static createRedirectSetup(e){let{slug:t,environment:n,domainRedirects:r=[],pathRedirects:i=[]}=e,s={},a=[];for(let c of r){let{bucket:l,bucketPolicy:u,logicalId:m,policyLogicalId:p}=At.createDomainRedirectBucket({...c,slug:t,environment:n});s[m]=l,s[p]=u,a.push(m)}let o=null;if(i.length>0){let{function:c,logicalId:l}=At.createPathRedirectFunction({slug:t,environment:n,rules:i});s[l]=c,o=l}return{resources:s,outputs:{domainRedirectBuckets:a,pathRedirectFunctionLogicalId:o}}}static fromMapping(e,t){return Object.entries(e).map(([n,r])=>({source:n,target:r,statusCode:t?.statusCode||301,preserveQueryString:t?.preserveQueryString??!0}))}static validateRules(e){let t=[],n=[],r=new Set;for(let i of e){if(r.has(i.source))t.push(`Duplicate source path: ${i.source}`);if(r.add(i.source),i.source===i.target)t.push(`Redirect loop detected: ${i.source} -> ${i.target}`);if(!i.target.startsWith("/")&&!i.target.startsWith("http"))n.push(`Target URL should start with / or http: ${i.target}`);if(!i.source||i.source.trim()==="")t.push("Source path cannot be empty");if(!i.target||i.target.trim()==="")t.push("Target path cannot be empty")}for(let i of e){let s=e.find((a)=>a.source===i.target);if(s)n.push(`Potential redirect chain: ${i.source} -> ${i.target} -> ${s.target}`)}return{valid:t.length===0,errors:t,warnings:n}}}class X{static generate(e){let t={},{slug:n,environment:r,region:i="us-east-1"}=e,s=X.createLambdaExecutionRole(n,r);if(Object.assign(t,s.resources),e.email?.enabled){let a=X.generateEmailResources(e,s.roleArn);Object.assign(t,a)}if(e.phone?.enabled){let a=X.generatePhoneResources(e,s.roleArn);Object.assign(t,a)}if(e.sms?.enabled){let a=X.generateSmsResources(e,s.roleArn);Object.assign(t,a)}return t}static createLambdaExecutionRole(e,t){let n=`${e}-${t}-communication-role`,r=f(n);return{resources:{[r]:{Type:"AWS::IAM::Role",Properties:{RoleName:n,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:C.GetAtt(r,"Arn"),roleName:n}}static generateEmailResources(e,t){let{slug:n,environment:r,email:i}=e;if(!i)return{};let s={},a=`${n}-${r}`,o=`${a}-email-storage`,c=f(o);s[c]={Type:"AWS::S3::Bucket",Properties:{BucketName:o,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:i.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:i.server.storage.archiveAfterDays}]:[],ExpirationInDays:i.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let l=f(`${a}-ses-identity`);if(s[l]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:i.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},i.notifications?.bounces||i.notifications?.complaints){let u=f(`${a}-bounce-topic`);s[u]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-email-bounces`}};let m=f(`${a}-complaint-topic`);s[m]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-email-complaints`}}}if(i.server?.enabled){let u=f(`${a}-inbound-email`);s[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:60,MemorySize:256,Code:{ZipFile:X.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:o,DOMAIN:i.domain}}}};let m=f(`${a}-outbound-email`);s[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:X.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:o,DOMAIN:i.domain}}}}}if(i.advanced?.analytics){let u=f(`${a}-email-analytics`);s[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(i.advanced?.scheduling){let u=f(`${a}-email-scheduler`);s[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:300,MemorySize:256,Code:{ZipFile:X.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:o}}}};let m=f(`${a}-email-scheduler-rule`);s[m]={Type:"AWS::Events::Rule",Properties:{Name:`${a}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:C.GetAtt(u,"Arn")}]}}}if(i.advanced?.threading){let u=f(`${a}-email-threading`);s[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:60,MemorySize:256,Code:{ZipFile:X.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:o}}}}}if(i.advanced?.rules){let u=f(`${a}-email-rules`);s[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-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(i.advanced?.sharedMailboxes){let u=f(`${a}-shared-mailboxes`);s[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-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(i.advanced?.search){let u=f(`${a}-email-search`);s[u]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${a}-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 s}static generatePhoneResources(e,t){let{slug:n,environment:r,phone:i}=e;if(!i)return{};let s={},a=`${n}-${r}`,o=f(`${a}-call-log`);if(s[o]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},i.voicemail?.enabled){let u=f(`${a}-voicemail`);s[u]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${a}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let c=f(`${a}-phone-notifications`);s[c]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-phone-notifications`}};let l=f(`${a}-incoming-call`);if(s[l]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:X.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${a}-call-log`,NOTIFICATION_TOPIC_ARN:C.Ref(c)}}}},i.voicemail?.enabled){let u=f(`${a}-voicemail-handler`);s[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:i.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:X.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${a}-voicemail`,TRANSCRIPTION_ENABLED:String(i.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:C.Ref(c)}}}}}if(i.advanced?.recording){let u=f(`${a}-call-recordings`);s[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(i.advanced?.callbacks){let u=f(`${a}-callbacks`);s[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(i.advanced?.analytics){let u=f(`${a}-call-metrics`);s[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return s}static generateSmsResources(e,t){let{slug:n,environment:r,sms:i}=e;if(!i)return{};let s={},a=`${n}-${r}`,o=f(`${a}-pinpoint-app`);s[o]={Type:"AWS::Pinpoint::App",Properties:{Name:`${a}-sms`}};let c=f(`${a}-sms-channel`);s[c]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:C.Ref(o),Enabled:!0,SenderId:i.senderId}};let l=f(`${a}-sms-log`);if(s[l]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-sms-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},i.optOut?.enabled){let g=f(`${a}-sms-optout`);s[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let u=f(`${a}-sms-notifications`);s[u]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-sms-notifications`}};let m=f(`${a}-send-sms`);s[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:X.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:C.Ref(o),MESSAGE_LOG_TABLE:`${a}-sms-log`,OPT_OUT_TABLE:i.optOut?.enabled?`${a}-sms-optout`:"",MESSAGE_TYPE:i.messageType||"TRANSACTIONAL"}}}};let p=f(`${a}-receive-sms`);if(s[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:X.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${a}-sms-log`,OPT_OUT_TABLE:i.optOut?.enabled?`${a}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:C.Ref(u)}}}},i.advanced?.campaigns){let g=f(`${a}-sms-campaigns`);s[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(i.advanced?.analytics){let g=f(`${a}-sms-analytics`);s[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(i.advanced?.linkTracking){let g=f(`${a}-short-links`);s[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(i.advanced?.chatbot){let g=f(`${a}-chatbot-sessions`);s[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let y=f(`${a}-chatbot-rules`);s[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(i.advanced?.abTesting){let g=f(`${a}-ab-tests`);s[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(i.advanced?.mms){let g=f(`${a}-mms-media`);s[g]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${a}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return s}static InboundEmailCode=`
2347
+ }`}static CommonRedirects={wwwToApex:(e,t="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${e}`,targetDomain:e,protocol:t,preservePath:!0}),apexToWww:(e,t="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:e,targetDomain:`www.${e}`,protocol:t,preservePath:!0}),httpToHttps:(e="/")=>({source:e,target:e,statusCode:301}),addTrailingSlash:(e)=>e.map((t)=>({source:t.endsWith("/")?t.slice(0,-1):t,target:t.endsWith("/")?t:`${t}/`,statusCode:301})),removeTrailingSlash:(e)=>e.map((t)=>({source:t.endsWith("/")&&t!=="/"?t:`${t}/`,target:t.endsWith("/")&&t!=="/"?t.slice(0,-1):t,statusCode:301}))};static Patterns={flattenBlogUrls:(e)=>e.map(({oldPath:t,newPath:n})=>({source:t,target:n,statusCode:301,preserveQueryString:!0})),categoryRename:(e,t)=>[{source:`/${e}`,target:`/${t}`,statusCode:301},{source:`/${e}/`,target:`/${t}/`,statusCode:301}],productSlugChange:(e)=>e.map(({oldSlug:t,newSlug:n})=>({source:`/products/${t}`,target:`/products/${n}`,statusCode:301})),apiVersionRedirect:(e,t,n)=>n.map((r)=>({source:`/api/${e}/${r}`,target:`/api/${t}/${r}`,statusCode:307,preserveQueryString:!0})),gonePages:(e)=>e.map((t)=>({source:t,target:"/410",statusCode:301}))};static createRedirectSetup(e){let{slug:t,environment:n,domainRedirects:r=[],pathRedirects:i=[]}=e,s={},a=[];for(let c of r){let{bucket:l,bucketPolicy:u,logicalId:m,policyLogicalId:p}=Ct.createDomainRedirectBucket({...c,slug:t,environment:n});s[m]=l,s[p]=u,a.push(m)}let o=null;if(i.length>0){let{function:c,logicalId:l}=Ct.createPathRedirectFunction({slug:t,environment:n,rules:i});s[l]=c,o=l}return{resources:s,outputs:{domainRedirectBuckets:a,pathRedirectFunctionLogicalId:o}}}static fromMapping(e,t){return Object.entries(e).map(([n,r])=>({source:n,target:r,statusCode:t?.statusCode||301,preserveQueryString:t?.preserveQueryString??!0}))}static validateRules(e){let t=[],n=[],r=new Set;for(let i of e){if(r.has(i.source))t.push(`Duplicate source path: ${i.source}`);if(r.add(i.source),i.source===i.target)t.push(`Redirect loop detected: ${i.source} -> ${i.target}`);if(!i.target.startsWith("/")&&!i.target.startsWith("http"))n.push(`Target URL should start with / or http: ${i.target}`);if(!i.source||i.source.trim()==="")t.push("Source path cannot be empty");if(!i.target||i.target.trim()==="")t.push("Target path cannot be empty")}for(let i of e){let s=e.find((a)=>a.source===i.target);if(s)n.push(`Potential redirect chain: ${i.source} -> ${i.target} -> ${s.target}`)}return{valid:t.length===0,errors:t,warnings:n}}}class ee{static generate(e){let t={},{slug:n,environment:r,region:i="us-east-1"}=e,s=ee.createLambdaExecutionRole(n,r);if(Object.assign(t,s.resources),e.email?.enabled){let a=ee.generateEmailResources(e,s.roleArn);Object.assign(t,a)}if(e.phone?.enabled){let a=ee.generatePhoneResources(e,s.roleArn);Object.assign(t,a)}if(e.sms?.enabled){let a=ee.generateSmsResources(e,s.roleArn);Object.assign(t,a)}return t}static createLambdaExecutionRole(e,t){let n=`${e}-${t}-communication-role`,r=f(n);return{resources:{[r]:{Type:"AWS::IAM::Role",Properties:{RoleName:n,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:v.GetAtt(r,"Arn"),roleName:n}}static generateEmailResources(e,t){let{slug:n,environment:r,email:i}=e;if(!i)return{};let s={},a=`${n}-${r}`,o=`${a}-email-storage`,c=f(o);s[c]={Type:"AWS::S3::Bucket",Properties:{BucketName:o,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:i.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:i.server.storage.archiveAfterDays}]:[],ExpirationInDays:i.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let l=f(`${a}-ses-identity`);if(s[l]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:i.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},i.notifications?.bounces||i.notifications?.complaints){let u=f(`${a}-bounce-topic`);s[u]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-email-bounces`}};let m=f(`${a}-complaint-topic`);s[m]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-email-complaints`}}}if(i.server?.enabled){let u=f(`${a}-inbound-email`);s[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:60,MemorySize:256,Code:{ZipFile:ee.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:o,DOMAIN:i.domain}}}};let m=f(`${a}-outbound-email`);s[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:ee.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:o,DOMAIN:i.domain}}}}}if(i.advanced?.analytics){let u=f(`${a}-email-analytics`);s[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(i.advanced?.scheduling){let u=f(`${a}-email-scheduler`);s[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:300,MemorySize:256,Code:{ZipFile:ee.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:o}}}};let m=f(`${a}-email-scheduler-rule`);s[m]={Type:"AWS::Events::Rule",Properties:{Name:`${a}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:v.GetAtt(u,"Arn")}]}}}if(i.advanced?.threading){let u=f(`${a}-email-threading`);s[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:60,MemorySize:256,Code:{ZipFile:ee.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:o}}}}}if(i.advanced?.rules){let u=f(`${a}-email-rules`);s[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-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(i.advanced?.sharedMailboxes){let u=f(`${a}-shared-mailboxes`);s[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-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(i.advanced?.search){let u=f(`${a}-email-search`);s[u]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${a}-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 s}static generatePhoneResources(e,t){let{slug:n,environment:r,phone:i}=e;if(!i)return{};let s={},a=`${n}-${r}`,o=f(`${a}-call-log`);if(s[o]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},i.voicemail?.enabled){let u=f(`${a}-voicemail`);s[u]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${a}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let c=f(`${a}-phone-notifications`);s[c]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-phone-notifications`}};let l=f(`${a}-incoming-call`);if(s[l]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:ee.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${a}-call-log`,NOTIFICATION_TOPIC_ARN:v.Ref(c)}}}},i.voicemail?.enabled){let u=f(`${a}-voicemail-handler`);s[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:i.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:ee.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${a}-voicemail`,TRANSCRIPTION_ENABLED:String(i.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:v.Ref(c)}}}}}if(i.advanced?.recording){let u=f(`${a}-call-recordings`);s[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(i.advanced?.callbacks){let u=f(`${a}-callbacks`);s[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(i.advanced?.analytics){let u=f(`${a}-call-metrics`);s[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return s}static generateSmsResources(e,t){let{slug:n,environment:r,sms:i}=e;if(!i)return{};let s={},a=`${n}-${r}`,o=f(`${a}-pinpoint-app`);s[o]={Type:"AWS::Pinpoint::App",Properties:{Name:`${a}-sms`}};let c=f(`${a}-sms-channel`);s[c]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:v.Ref(o),Enabled:!0,SenderId:i.senderId}};let l=f(`${a}-sms-log`);if(s[l]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-sms-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},i.optOut?.enabled){let g=f(`${a}-sms-optout`);s[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let u=f(`${a}-sms-notifications`);s[u]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-sms-notifications`}};let m=f(`${a}-send-sms`);s[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:ee.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:v.Ref(o),MESSAGE_LOG_TABLE:`${a}-sms-log`,OPT_OUT_TABLE:i.optOut?.enabled?`${a}-sms-optout`:"",MESSAGE_TYPE:i.messageType||"TRANSACTIONAL"}}}};let p=f(`${a}-receive-sms`);if(s[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:ee.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${a}-sms-log`,OPT_OUT_TABLE:i.optOut?.enabled?`${a}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:v.Ref(u)}}}},i.advanced?.campaigns){let g=f(`${a}-sms-campaigns`);s[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(i.advanced?.analytics){let g=f(`${a}-sms-analytics`);s[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(i.advanced?.linkTracking){let g=f(`${a}-short-links`);s[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(i.advanced?.chatbot){let g=f(`${a}-chatbot-sessions`);s[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let y=f(`${a}-chatbot-rules`);s[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(i.advanced?.abTesting){let g=f(`${a}-ab-tests`);s[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(i.advanced?.mms){let g=f(`${a}-mms-media`);s[g]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${a}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return s}static InboundEmailCode=`
2348
2348
  const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
2349
2349
  const s3 = new S3Client({});
2350
2350
  exports.handler = async (event) => {
@@ -2442,7 +2442,7 @@ exports.handler = async (event) => {
2442
2442
  console.log('Receive SMS:', JSON.stringify(event, null, 2));
2443
2443
  // Process inbound SMS, handle opt-out keywords
2444
2444
  return { statusCode: 200 };
2445
- };`}var d={ref:(e)=>({Ref:e}),getAtt:(e,t)=>({"Fn::GetAtt":[e,t]}),join:(e,t)=>({"Fn::Join":[e,t]}),sub:(e,t)=>t?{"Fn::Sub":[e,t]}:{"Fn::Sub":e},select:(e,t)=>({"Fn::Select":[e,t]}),split:(e,t)=>({"Fn::Split":[e,t]}),getAZs:(e="")=>({"Fn::GetAZs":e}),importValue:(e)=>({"Fn::ImportValue":e}),findInMap:(e,t,n)=>({"Fn::FindInMap":[e,t,n]}),base64:(e)=>({"Fn::Base64":e}),cidr:(e,t,n)=>({"Fn::Cidr":[e,t,n]}),equals:(e,t)=>({"Fn::Equals":[e,t]}),if:(e,t,n)=>({"Fn::If":[e,t,n]}),not:(e)=>({"Fn::Not":[e]}),and:(...e)=>({"Fn::And":e}),or:(...e)=>({"Fn::Or":e})},Fe={s3Bucket:(e)=>d.sub(`arn:aws:s3:::${e}`),s3Object:(e,t="*")=>d.sub(`arn:aws:s3:::${e}/${t}`),lambda:(e,t,n)=>d.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${e}`,t&&n?{"AWS::Region":t,"AWS::AccountId":n}:void 0),dynamodb:(e)=>d.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${e}`),sqs:(e)=>d.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${e}`),sns:(e)=>d.sub(`arn:aws:sns:\${AWS::Region}:\${AWS::AccountId}:${e}`),kinesis:(e)=>d.sub(`arn:aws:kinesis:\${AWS::Region}:\${AWS::AccountId}:stream/${e}`),iam:(e,t)=>d.sub(`arn:aws:iam::\${AWS::AccountId}:${e}/${t}`),secretsManager:(e)=>d.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${e}`),cloudwatch:(e)=>d.sub(`arn:aws:logs:\${AWS::Region}:\${AWS::AccountId}:log-group:${e}`)},fp={ACCOUNT_ID:{Ref:"AWS::AccountId"},NOTIFICATION_ARNS:{Ref:"AWS::NotificationARNs"},NO_VALUE:{Ref:"AWS::NoValue"},PARTITION:{Ref:"AWS::Partition"},REGION:{Ref:"AWS::Region"},STACK_ID:{Ref:"AWS::StackId"},STACK_NAME:{Ref:"AWS::StackName"},URL_SUFFIX:{Ref:"AWS::URLSuffix"}};function Sr(e,t){if(t.type==="http")La(e,t);else if(t.type==="rest")Oa(e,t);else if(t.type==="websocket")$a(e,t)}function La(e,t){let n={Name:d.sub("${AWS::StackName}-http-api"),ProtocolType:"HTTP"};if(t.cors)n.CorsConfiguration={AllowOrigins:t.cors.allowOrigins,AllowMethods:t.cors.allowMethods,AllowHeaders:t.cors.allowHeaders||["*"],MaxAge:t.cors.maxAge||300};if(e.addResource("HttpApi","AWS::ApiGatewayV2::Api",n),e.addResource("HttpApiStage","AWS::ApiGatewayV2::Stage",{ApiId:d.ref("HttpApi"),StageName:"$default",AutoDeploy:!0,DefaultRouteSettings:t.throttling?{ThrottlingBurstLimit:t.throttling.burstLimit,ThrottlingRateLimit:t.throttling.rateLimit}:void 0,AccessLogSettings:{DestinationArn:d.getAtt("ApiLogGroup","Arn"),Format:"$context.requestId $context.error.message $context.error.messageString"}},{dependsOn:["HttpApi","ApiLogGroup"]}),e.addResource("ApiLogGroup","AWS::Logs::LogGroup",{LogGroupName:d.sub("/aws/apigateway/${AWS::StackName}-http-api"),RetentionInDays:14}),t.authorizer)Ba(e,"HttpApi",t.authorizer);if(t.customDomain)Jt(e,"HttpApi",t.customDomain,"HTTP");e.addOutputs({HttpApiId:{Description:"HTTP API ID",Value:d.ref("HttpApi"),Export:{Name:d.sub("${AWS::StackName}-http-api-id")}},HttpApiEndpoint:{Description:"HTTP API endpoint",Value:d.getAtt("HttpApi","ApiEndpoint"),Export:{Name:d.sub("${AWS::StackName}-http-api-endpoint")}}})}function Oa(e,t){e.addResource("RestApi","AWS::ApiGateway::RestApi",{Name:d.sub("${AWS::StackName}-rest-api"),Description:d.sub("REST API for ${AWS::StackName}"),EndpointConfiguration:{Types:["REGIONAL"]}}),e.addResource("ApiGatewayAccount","AWS::ApiGateway::Account",{CloudWatchRoleArn:d.getAtt("ApiGatewayCloudWatchRole","Arn")},{dependsOn:"ApiGatewayCloudWatchRole"}),e.addResource("ApiGatewayCloudWatchRole","AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"apigateway.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"]}),e.addResource("RestApiDeployment","AWS::ApiGateway::Deployment",{RestApiId:d.ref("RestApi"),Description:"Initial deployment"},{dependsOn:"RestApi"});let n={RestApiId:d.ref("RestApi"),DeploymentId:d.ref("RestApiDeployment"),StageName:"prod",Description:"Production stage",MethodSettings:[{ResourcePath:"/*",HttpMethod:"*",LoggingLevel:"INFO",DataTraceEnabled:!0,MetricsEnabled:!0}]};if(t.throttling)n.MethodSettings[0].ThrottlingBurstLimit=t.throttling.burstLimit,n.MethodSettings[0].ThrottlingRateLimit=t.throttling.rateLimit;if(e.addResource("RestApiStage","AWS::ApiGateway::Stage",n,{dependsOn:["RestApi","RestApiDeployment"]}),t.customDomain)Jt(e,"RestApi",t.customDomain,"REST");e.addOutputs({RestApiId:{Description:"REST API ID",Value:d.ref("RestApi"),Export:{Name:d.sub("${AWS::StackName}-rest-api-id")}},RestApiEndpoint:{Description:"REST API endpoint",Value:d.sub("https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/prod"),Export:{Name:d.sub("${AWS::StackName}-rest-api-endpoint")}}})}function $a(e,t){if(e.addResource("WebSocketApi","AWS::ApiGatewayV2::Api",{Name:d.sub("${AWS::StackName}-websocket-api"),ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action"}),t.routes){if(t.routes.connect)Ct(e,"$connect",t.routes.connect.functionName);if(t.routes.disconnect)Ct(e,"$disconnect",t.routes.disconnect.functionName);if(t.routes.default)Ct(e,"$default",t.routes.default.functionName);if(t.routes.custom)t.routes.custom.forEach((n)=>{Ct(e,n.routeKey,n.functionName)})}if(e.addResource("WebSocketApiStage","AWS::ApiGatewayV2::Stage",{ApiId:d.ref("WebSocketApi"),StageName:"prod",AutoDeploy:!0,DefaultRouteSettings:t.throttling?{ThrottlingBurstLimit:t.throttling.burstLimit,ThrottlingRateLimit:t.throttling.rateLimit}:void 0},{dependsOn:"WebSocketApi"}),t.customDomain)Jt(e,"WebSocketApi",t.customDomain,"WEBSOCKET");e.addOutputs({WebSocketApiId:{Description:"WebSocket API ID",Value:d.ref("WebSocketApi"),Export:{Name:d.sub("${AWS::StackName}-websocket-api-id")}},WebSocketApiEndpoint:{Description:"WebSocket API endpoint",Value:d.getAtt("WebSocketApi","ApiEndpoint"),Export:{Name:d.sub("${AWS::StackName}-websocket-api-endpoint")}}})}function Ct(e,t,n){let r=e.toLogicalId(`websocket-route-${t}`),i=e.toLogicalId(`websocket-integration-${t}`),s=e.toLogicalId(`${n}-function`);e.addResource(i,"AWS::ApiGatewayV2::Integration",{ApiId:d.ref("WebSocketApi"),IntegrationType:"AWS_PROXY",IntegrationUri:d.sub(`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${s}.Arn}/invocations`)},{dependsOn:["WebSocketApi",s]}),e.addResource(r,"AWS::ApiGatewayV2::Route",{ApiId:d.ref("WebSocketApi"),RouteKey:t,Target:d.join("/",["integrations",d.ref(i)])},{dependsOn:["WebSocketApi",i]}),e.addResource(`${r}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(s),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:d.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*")},{dependsOn:[s,"WebSocketApi"]})}function Jt(e,t,n,r){let i={DomainName:n.domain};if(r==="REST")i.CertificateArn=n.certificateArn,i.EndpointConfiguration={Types:["REGIONAL"]},e.addResource("ApiCustomDomain","AWS::ApiGateway::DomainName",i),e.addResource("ApiBasePathMapping","AWS::ApiGateway::BasePathMapping",{DomainName:d.ref("ApiCustomDomain"),RestApiId:d.ref(t),Stage:d.ref("RestApiStage")},{dependsOn:["ApiCustomDomain",t,"RestApiStage"]});else i.DomainNameConfigurations=[{CertificateArn:n.certificateArn,EndpointType:"REGIONAL"}],e.addResource("ApiCustomDomain","AWS::ApiGatewayV2::DomainName",i),e.addResource("ApiMapping","AWS::ApiGatewayV2::ApiMapping",{ApiId:d.ref(t),DomainName:d.ref("ApiCustomDomain"),Stage:r==="HTTP"?d.ref("HttpApiStage"):d.ref("WebSocketApiStage")},{dependsOn:["ApiCustomDomain",t]});if(n.dnsProvider!=="external")e.addResource("ApiDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:d.sub(`${Fa(n.domain)}.`),Name:n.domain,Type:"A",AliasTarget:{HostedZoneId:d.getAtt("ApiCustomDomain","RegionalHostedZoneId"),DNSName:d.getAtt("ApiCustomDomain","RegionalDomainName"),EvaluateTargetHealth:!1}},{dependsOn:"ApiCustomDomain"});e.addOutputs({ApiCustomDomainName:{Description:"Configured API custom domain",Value:n.domain},ApiCustomDomainTarget:{Description:"DNS target for Route53 or an external DNS provider",Value:d.getAtt("ApiCustomDomain","RegionalDomainName")},ApiCustomDomainHostedZoneId:{Description:"Regional API Gateway hosted zone ID",Value:d.getAtt("ApiCustomDomain","RegionalHostedZoneId")}})}function Ba(e,t,n){if(!n)return;if(n.type==="jwt")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:d.ref(t),AuthorizerType:"JWT",IdentitySource:[n.identitySource||"$request.header.Authorization"],JwtConfiguration:{Issuer:n.issuer,Audience:n.audience},Name:"JWTAuthorizer"},{dependsOn:t});else if(n.type==="lambda")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:d.ref(t),AuthorizerType:"REQUEST",AuthorizerUri:n.authorizerUri,IdentitySource:[n.identitySource||"$request.header.Authorization"],Name:"LambdaAuthorizer"},{dependsOn:t})}function Fa(e){let t=e.split(".");if(t.length>=2)return t.slice(-2).join(".");return e}function Ar(e,t){if(t.redis)Ga(e,t.redis);if(t.memcached)_a(e,t.memcached);if(t.elasticache)Wa(e,t.elasticache)}function Ga(e,t){if(!t)return;if(e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache Redis cluster",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Redis",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:t.port||6379,ToPort:t.port||6379,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]}),t.parameterGroup&&Object.keys(t.parameterGroup).length>0)e.addResource("CacheParameterGroup","AWS::ElastiCache::ParameterGroup",{Description:"Parameter group for Redis",CacheParameterGroupFamily:`redis${t.engineVersion.split(".")[0]}`,Properties:t.parameterGroup});if(t.numCacheNodes>1||t.automaticFailoverEnabled)e.addResource("RedisReplicationGroup","AWS::ElastiCache::ReplicationGroup",{ReplicationGroupDescription:"Redis replication group",ReplicationGroupId:d.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheClusters:t.numCacheNodes,AutomaticFailoverEnabled:t.automaticFailoverEnabled||!1,MultiAZEnabled:t.automaticFailoverEnabled||!1,Port:t.port||6379,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),SecurityGroupIds:[d.ref("CacheSecurityGroup")],CacheParameterGroupName:t.parameterGroup?d.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:t.snapshotRetentionLimit||5,SnapshotWindow:t.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",AtRestEncryptionEnabled:!0,TransitEncryptionEnabled:!0,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-redis")}]},{dependsOn:t.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis primary endpoint",Value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address"),Export:{Name:d.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port"),Export:{Name:d.sub("${AWS::StackName}-redis-port")}}});else e.addResource("RedisCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:d.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheNodes:1,Port:t.port||6379,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[d.ref("CacheSecurityGroup")],CacheParameterGroupName:t.parameterGroup?d.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:t.snapshotRetentionLimit||5,SnapshotWindow:t.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-redis")}]},{dependsOn:t.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis endpoint",Value:d.getAtt("RedisCacheCluster","RedisEndpoint.Address"),Export:{Name:d.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:d.getAtt("RedisCacheCluster","RedisEndpoint.Port"),Export:{Name:d.sub("${AWS::StackName}-redis-port")}}})}function _a(e,t){if(!t)return;if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Memcached",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:t.port||11211,ToPort:t.port||11211,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("MemcachedCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:d.sub("${AWS::StackName}-memcached"),Engine:"memcached",EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheNodes:t.numCacheNodes,Port:t.port||11211,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[d.ref("CacheSecurityGroup")],PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-memcached")}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]}),e.addOutputs({MemcachedEndpoint:{Description:"Memcached configuration endpoint",Value:d.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Address"),Export:{Name:d.sub("${AWS::StackName}-memcached-endpoint")}},MemcachedPort:{Description:"Memcached port",Value:d.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Port"),Export:{Name:d.sub("${AWS::StackName}-memcached-port")}}})}function Wa(e,t){if(!t)return;let n=t.engine==="redis";if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:n?6379:11211,ToPort:n?6379:11211,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("CacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:d.sub(`\${AWS::StackName}-${t.engine}`),Engine:t.engine,EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheNodes:t.numCacheNodes,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[d.ref("CacheSecurityGroup")],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.engine}`)}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]})}function Cr(e,t){if(!t.enabled)return;e.addResource("CloudFrontOriginAccessIdentity","AWS::CloudFront::CloudFrontOriginAccessIdentity",{CloudFrontOriginAccessIdentityConfig:{Comment:d.sub("${AWS::StackName} CloudFront OAI")}});let n=[],r=[];if(!t.origins||t.origins.length===0)n.push({Id:"S3Origin",DomainName:d.getAtt("StaticBucket","DomainName"),S3OriginConfig:{OriginAccessIdentity:d.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")}});else t.origins.forEach((a,o)=>{let c={Id:a.id,DomainName:a.domainName};if(a.originPath)c.OriginPath=a.originPath;if(a.domainName.includes("s3"))c.S3OriginConfig={OriginAccessIdentity:d.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")};else c.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"]};if(n.push(c),o>0||a.pathPattern)r.push({PathPattern:a.pathPattern||`/${a.id}/*`,TargetOriginId:a.id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:t.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:t.cachePolicy?.minTTL||0,DefaultTTL:t.cachePolicy?.defaultTTL||86400,MaxTTL:t.cachePolicy?.maxTTL||31536000})});let i={TargetOriginId:n[0].Id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:t.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:t.cachePolicy?.minTTL||0,DefaultTTL:t.cachePolicy?.defaultTTL||86400,MaxTTL:t.cachePolicy?.maxTTL||31536000};if(t.edgeFunctions&&t.edgeFunctions.length>0)i.LambdaFunctionAssociations=t.edgeFunctions.map((a)=>({EventType:a.eventType,LambdaFunctionARN:a.functionArn}));let s={Enabled:!0,HttpVersion:t.http3?"http3":"http2",IPV6Enabled:!0,Origins:n,DefaultCacheBehavior:i,PriceClass:t.priceClass||"PriceClass_100",ViewerCertificate:{}};if(r.length>0)s.CacheBehaviors=r;if(t.customDomain)s.Aliases=[t.customDomain.domain],s.ViewerCertificate={AcmCertificateArn:t.customDomain.certificateArn,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else s.ViewerCertificate={CloudFrontDefaultCertificate:!0};if(t.errorPages)s.CustomErrorResponses=Object.entries(t.errorPages).map(([a,o])=>({ErrorCode:Number.parseInt(a),ResponseCode:200,ResponsePagePath:o,ErrorCachingMinTTL:300}));if(s.DefaultRootObject="index.html",s.Comment=d.sub("${AWS::StackName} CloudFront Distribution"),e.addResource("CloudFrontDistribution","AWS::CloudFront::Distribution",{DistributionConfig:s},{dependsOn:"CloudFrontOriginAccessIdentity"}),!t.origins||t.origins.length===0)e.addResource("StaticBucketPolicyForCloudFront","AWS::S3::BucketPolicy",{Bucket:d.ref("StaticBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontAccess",Effect:"Allow",Principal:{CanonicalUser:d.getAtt("CloudFrontOriginAccessIdentity","S3CanonicalUserId")},Action:"s3:GetObject",Resource:d.join("",[d.getAtt("StaticBucket","Arn"),"/*"])}]}},{dependsOn:["StaticBucket","CloudFrontOriginAccessIdentity"]});if(t.customDomain)e.addResource("CloudFrontDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:d.sub(`${Va(t.customDomain.domain)}.`),Name:t.customDomain.domain,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:d.getAtt("CloudFrontDistribution","DomainName"),EvaluateTargetHealth:!1}},{dependsOn:"CloudFrontDistribution"});if(e.addOutputs({CloudFrontDistributionId:{Description:"CloudFront distribution ID",Value:d.ref("CloudFrontDistribution"),Export:{Name:d.sub("${AWS::StackName}-cloudfront-id")}},CloudFrontDomainName:{Description:"CloudFront distribution domain name",Value:d.getAtt("CloudFrontDistribution","DomainName"),Export:{Name:d.sub("${AWS::StackName}-cloudfront-domain")}}}),t.customDomain)e.addOutputs({CloudFrontURL:{Description:"CloudFront custom domain URL",Value:d.sub(`https://${t.customDomain.domain}`)}})}function Va(e){let t=e.split(".");if(t.length>=2)return t.slice(-2).join(".");return e}function Tr(e,t){if(t.server)Ua(e,t.server);if(t.fargate)vr(e,"app",t.fargate);if(t.services)t.services.forEach((n)=>{if(n.type==="fargate")vr(e,n.name,{taskDefinition:n.taskDefinition,service:n.service})})}function Ua(e,t){if(!t)return;e.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for application instances",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:3000,ToPort:3000,SourceSecurityGroupId:d.ref("ALBSecurityGroup")},{IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:"0.0.0.0/0"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-app-sg")}]},{dependsOn:"VPC"}),e.addResource("EC2InstanceRole","AWS::IAM::Role",{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"],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-ec2-role")}]}),e.addResource("EC2InstanceProfile","AWS::IAM::InstanceProfile",{Roles:[d.ref("EC2InstanceRole")]},{dependsOn:"EC2InstanceRole"});let n=t.userData||`#!/bin/bash
2445
+ };`}var d={ref:(e)=>({Ref:e}),getAtt:(e,t)=>({"Fn::GetAtt":[e,t]}),join:(e,t)=>({"Fn::Join":[e,t]}),sub:(e,t)=>t?{"Fn::Sub":[e,t]}:{"Fn::Sub":e},select:(e,t)=>({"Fn::Select":[e,t]}),split:(e,t)=>({"Fn::Split":[e,t]}),getAZs:(e="")=>({"Fn::GetAZs":e}),importValue:(e)=>({"Fn::ImportValue":e}),findInMap:(e,t,n)=>({"Fn::FindInMap":[e,t,n]}),base64:(e)=>({"Fn::Base64":e}),cidr:(e,t,n)=>({"Fn::Cidr":[e,t,n]}),equals:(e,t)=>({"Fn::Equals":[e,t]}),if:(e,t,n)=>({"Fn::If":[e,t,n]}),not:(e)=>({"Fn::Not":[e]}),and:(...e)=>({"Fn::And":e}),or:(...e)=>({"Fn::Or":e})},_e={s3Bucket:(e)=>d.sub(`arn:aws:s3:::${e}`),s3Object:(e,t="*")=>d.sub(`arn:aws:s3:::${e}/${t}`),lambda:(e,t,n)=>d.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${e}`,t&&n?{"AWS::Region":t,"AWS::AccountId":n}:void 0),dynamodb:(e)=>d.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${e}`),sqs:(e)=>d.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${e}`),sns:(e)=>d.sub(`arn:aws:sns:\${AWS::Region}:\${AWS::AccountId}:${e}`),kinesis:(e)=>d.sub(`arn:aws:kinesis:\${AWS::Region}:\${AWS::AccountId}:stream/${e}`),iam:(e,t)=>d.sub(`arn:aws:iam::\${AWS::AccountId}:${e}/${t}`),secretsManager:(e)=>d.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${e}`),cloudwatch:(e)=>d.sub(`arn:aws:logs:\${AWS::Region}:\${AWS::AccountId}:log-group:${e}`)},fp={ACCOUNT_ID:{Ref:"AWS::AccountId"},NOTIFICATION_ARNS:{Ref:"AWS::NotificationARNs"},NO_VALUE:{Ref:"AWS::NoValue"},PARTITION:{Ref:"AWS::Partition"},REGION:{Ref:"AWS::Region"},STACK_ID:{Ref:"AWS::StackId"},STACK_NAME:{Ref:"AWS::StackName"},URL_SUFFIX:{Ref:"AWS::URLSuffix"}};function Sr(e,t){if(t.type==="http")La(e,t);else if(t.type==="rest")Oa(e,t);else if(t.type==="websocket")$a(e,t)}function La(e,t){let n={Name:d.sub("${AWS::StackName}-http-api"),ProtocolType:"HTTP"};if(t.cors)n.CorsConfiguration={AllowOrigins:t.cors.allowOrigins,AllowMethods:t.cors.allowMethods,AllowHeaders:t.cors.allowHeaders||["*"],MaxAge:t.cors.maxAge||300};if(e.addResource("HttpApi","AWS::ApiGatewayV2::Api",n),e.addResource("HttpApiStage","AWS::ApiGatewayV2::Stage",{ApiId:d.ref("HttpApi"),StageName:"$default",AutoDeploy:!0,DefaultRouteSettings:t.throttling?{ThrottlingBurstLimit:t.throttling.burstLimit,ThrottlingRateLimit:t.throttling.rateLimit}:void 0,AccessLogSettings:{DestinationArn:d.getAtt("ApiLogGroup","Arn"),Format:"$context.requestId $context.error.message $context.error.messageString"}},{dependsOn:["HttpApi","ApiLogGroup"]}),e.addResource("ApiLogGroup","AWS::Logs::LogGroup",{LogGroupName:d.sub("/aws/apigateway/${AWS::StackName}-http-api"),RetentionInDays:14}),t.authorizer)Ba(e,"HttpApi",t.authorizer);if(t.customDomain)Jt(e,"HttpApi",t.customDomain,"HTTP");e.addOutputs({HttpApiId:{Description:"HTTP API ID",Value:d.ref("HttpApi"),Export:{Name:d.sub("${AWS::StackName}-http-api-id")}},HttpApiEndpoint:{Description:"HTTP API endpoint",Value:d.getAtt("HttpApi","ApiEndpoint"),Export:{Name:d.sub("${AWS::StackName}-http-api-endpoint")}}})}function Oa(e,t){e.addResource("RestApi","AWS::ApiGateway::RestApi",{Name:d.sub("${AWS::StackName}-rest-api"),Description:d.sub("REST API for ${AWS::StackName}"),EndpointConfiguration:{Types:["REGIONAL"]}}),e.addResource("ApiGatewayAccount","AWS::ApiGateway::Account",{CloudWatchRoleArn:d.getAtt("ApiGatewayCloudWatchRole","Arn")},{dependsOn:"ApiGatewayCloudWatchRole"}),e.addResource("ApiGatewayCloudWatchRole","AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"apigateway.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"]}),e.addResource("RestApiDeployment","AWS::ApiGateway::Deployment",{RestApiId:d.ref("RestApi"),Description:"Initial deployment"},{dependsOn:"RestApi"});let n={RestApiId:d.ref("RestApi"),DeploymentId:d.ref("RestApiDeployment"),StageName:"prod",Description:"Production stage",MethodSettings:[{ResourcePath:"/*",HttpMethod:"*",LoggingLevel:"INFO",DataTraceEnabled:!0,MetricsEnabled:!0}]};if(t.throttling)n.MethodSettings[0].ThrottlingBurstLimit=t.throttling.burstLimit,n.MethodSettings[0].ThrottlingRateLimit=t.throttling.rateLimit;if(e.addResource("RestApiStage","AWS::ApiGateway::Stage",n,{dependsOn:["RestApi","RestApiDeployment"]}),t.customDomain)Jt(e,"RestApi",t.customDomain,"REST");e.addOutputs({RestApiId:{Description:"REST API ID",Value:d.ref("RestApi"),Export:{Name:d.sub("${AWS::StackName}-rest-api-id")}},RestApiEndpoint:{Description:"REST API endpoint",Value:d.sub("https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/prod"),Export:{Name:d.sub("${AWS::StackName}-rest-api-endpoint")}}})}function $a(e,t){if(e.addResource("WebSocketApi","AWS::ApiGatewayV2::Api",{Name:d.sub("${AWS::StackName}-websocket-api"),ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action"}),t.routes){if(t.routes.connect)vt(e,"$connect",t.routes.connect.functionName);if(t.routes.disconnect)vt(e,"$disconnect",t.routes.disconnect.functionName);if(t.routes.default)vt(e,"$default",t.routes.default.functionName);if(t.routes.custom)t.routes.custom.forEach((n)=>{vt(e,n.routeKey,n.functionName)})}if(e.addResource("WebSocketApiStage","AWS::ApiGatewayV2::Stage",{ApiId:d.ref("WebSocketApi"),StageName:"prod",AutoDeploy:!0,DefaultRouteSettings:t.throttling?{ThrottlingBurstLimit:t.throttling.burstLimit,ThrottlingRateLimit:t.throttling.rateLimit}:void 0},{dependsOn:"WebSocketApi"}),t.customDomain)Jt(e,"WebSocketApi",t.customDomain,"WEBSOCKET");e.addOutputs({WebSocketApiId:{Description:"WebSocket API ID",Value:d.ref("WebSocketApi"),Export:{Name:d.sub("${AWS::StackName}-websocket-api-id")}},WebSocketApiEndpoint:{Description:"WebSocket API endpoint",Value:d.getAtt("WebSocketApi","ApiEndpoint"),Export:{Name:d.sub("${AWS::StackName}-websocket-api-endpoint")}}})}function vt(e,t,n){let r=e.toLogicalId(`websocket-route-${t}`),i=e.toLogicalId(`websocket-integration-${t}`),s=e.toLogicalId(`${n}-function`);e.addResource(i,"AWS::ApiGatewayV2::Integration",{ApiId:d.ref("WebSocketApi"),IntegrationType:"AWS_PROXY",IntegrationUri:d.sub(`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${s}.Arn}/invocations`)},{dependsOn:["WebSocketApi",s]}),e.addResource(r,"AWS::ApiGatewayV2::Route",{ApiId:d.ref("WebSocketApi"),RouteKey:t,Target:d.join("/",["integrations",d.ref(i)])},{dependsOn:["WebSocketApi",i]}),e.addResource(`${r}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(s),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:d.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*")},{dependsOn:[s,"WebSocketApi"]})}function Jt(e,t,n,r){let i={DomainName:n.domain};if(r==="REST")i.CertificateArn=n.certificateArn,i.EndpointConfiguration={Types:["REGIONAL"]},e.addResource("ApiCustomDomain","AWS::ApiGateway::DomainName",i),e.addResource("ApiBasePathMapping","AWS::ApiGateway::BasePathMapping",{DomainName:d.ref("ApiCustomDomain"),RestApiId:d.ref(t),Stage:d.ref("RestApiStage")},{dependsOn:["ApiCustomDomain",t,"RestApiStage"]});else i.DomainNameConfigurations=[{CertificateArn:n.certificateArn,EndpointType:"REGIONAL"}],e.addResource("ApiCustomDomain","AWS::ApiGatewayV2::DomainName",i),e.addResource("ApiMapping","AWS::ApiGatewayV2::ApiMapping",{ApiId:d.ref(t),DomainName:d.ref("ApiCustomDomain"),Stage:r==="HTTP"?d.ref("HttpApiStage"):d.ref("WebSocketApiStage")},{dependsOn:["ApiCustomDomain",t]});if(n.dnsProvider!=="external")e.addResource("ApiDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:d.sub(`${Fa(n.domain)}.`),Name:n.domain,Type:"A",AliasTarget:{HostedZoneId:d.getAtt("ApiCustomDomain","RegionalHostedZoneId"),DNSName:d.getAtt("ApiCustomDomain","RegionalDomainName"),EvaluateTargetHealth:!1}},{dependsOn:"ApiCustomDomain"});e.addOutputs({ApiCustomDomainName:{Description:"Configured API custom domain",Value:n.domain},ApiCustomDomainTarget:{Description:"DNS target for Route53 or an external DNS provider",Value:d.getAtt("ApiCustomDomain","RegionalDomainName")},ApiCustomDomainHostedZoneId:{Description:"Regional API Gateway hosted zone ID",Value:d.getAtt("ApiCustomDomain","RegionalHostedZoneId")}})}function Ba(e,t,n){if(!n)return;if(n.type==="jwt")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:d.ref(t),AuthorizerType:"JWT",IdentitySource:[n.identitySource||"$request.header.Authorization"],JwtConfiguration:{Issuer:n.issuer,Audience:n.audience},Name:"JWTAuthorizer"},{dependsOn:t});else if(n.type==="lambda")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:d.ref(t),AuthorizerType:"REQUEST",AuthorizerUri:n.authorizerUri,IdentitySource:[n.identitySource||"$request.header.Authorization"],Name:"LambdaAuthorizer"},{dependsOn:t})}function Fa(e){let t=e.split(".");if(t.length>=2)return t.slice(-2).join(".");return e}function Ar(e,t){if(t.redis)Ga(e,t.redis);if(t.memcached)_a(e,t.memcached);if(t.elasticache)Wa(e,t.elasticache)}function Ga(e,t){if(!t)return;if(e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache Redis cluster",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Redis",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:t.port||6379,ToPort:t.port||6379,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]}),t.parameterGroup&&Object.keys(t.parameterGroup).length>0)e.addResource("CacheParameterGroup","AWS::ElastiCache::ParameterGroup",{Description:"Parameter group for Redis",CacheParameterGroupFamily:`redis${t.engineVersion.split(".")[0]}`,Properties:t.parameterGroup});if(t.numCacheNodes>1||t.automaticFailoverEnabled)e.addResource("RedisReplicationGroup","AWS::ElastiCache::ReplicationGroup",{ReplicationGroupDescription:"Redis replication group",ReplicationGroupId:d.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheClusters:t.numCacheNodes,AutomaticFailoverEnabled:t.automaticFailoverEnabled||!1,MultiAZEnabled:t.automaticFailoverEnabled||!1,Port:t.port||6379,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),SecurityGroupIds:[d.ref("CacheSecurityGroup")],CacheParameterGroupName:t.parameterGroup?d.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:t.snapshotRetentionLimit||5,SnapshotWindow:t.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",AtRestEncryptionEnabled:!0,TransitEncryptionEnabled:!0,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-redis")}]},{dependsOn:t.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis primary endpoint",Value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address"),Export:{Name:d.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port"),Export:{Name:d.sub("${AWS::StackName}-redis-port")}}});else e.addResource("RedisCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:d.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheNodes:1,Port:t.port||6379,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[d.ref("CacheSecurityGroup")],CacheParameterGroupName:t.parameterGroup?d.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:t.snapshotRetentionLimit||5,SnapshotWindow:t.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-redis")}]},{dependsOn:t.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis endpoint",Value:d.getAtt("RedisCacheCluster","RedisEndpoint.Address"),Export:{Name:d.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:d.getAtt("RedisCacheCluster","RedisEndpoint.Port"),Export:{Name:d.sub("${AWS::StackName}-redis-port")}}})}function _a(e,t){if(!t)return;if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Memcached",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:t.port||11211,ToPort:t.port||11211,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("MemcachedCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:d.sub("${AWS::StackName}-memcached"),Engine:"memcached",EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheNodes:t.numCacheNodes,Port:t.port||11211,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[d.ref("CacheSecurityGroup")],PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-memcached")}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]}),e.addOutputs({MemcachedEndpoint:{Description:"Memcached configuration endpoint",Value:d.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Address"),Export:{Name:d.sub("${AWS::StackName}-memcached-endpoint")}},MemcachedPort:{Description:"Memcached port",Value:d.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Port"),Export:{Name:d.sub("${AWS::StackName}-memcached-port")}}})}function Wa(e,t){if(!t)return;let n=t.engine==="redis";if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:n?6379:11211,ToPort:n?6379:11211,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("CacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:d.sub(`\${AWS::StackName}-${t.engine}`),Engine:t.engine,EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheNodes:t.numCacheNodes,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[d.ref("CacheSecurityGroup")],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.engine}`)}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]})}function Cr(e,t){if(!t.enabled)return;e.addResource("CloudFrontOriginAccessIdentity","AWS::CloudFront::CloudFrontOriginAccessIdentity",{CloudFrontOriginAccessIdentityConfig:{Comment:d.sub("${AWS::StackName} CloudFront OAI")}});let n=[],r=[];if(!t.origins||t.origins.length===0)n.push({Id:"S3Origin",DomainName:d.getAtt("StaticBucket","DomainName"),S3OriginConfig:{OriginAccessIdentity:d.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")}});else t.origins.forEach((a,o)=>{let c={Id:a.id,DomainName:a.domainName};if(a.originPath)c.OriginPath=a.originPath;if(a.domainName.includes("s3"))c.S3OriginConfig={OriginAccessIdentity:d.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")};else c.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"]};if(n.push(c),o>0||a.pathPattern)r.push({PathPattern:a.pathPattern||`/${a.id}/*`,TargetOriginId:a.id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:t.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:t.cachePolicy?.minTTL||0,DefaultTTL:t.cachePolicy?.defaultTTL||86400,MaxTTL:t.cachePolicy?.maxTTL||31536000})});let i={TargetOriginId:n[0].Id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:t.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:t.cachePolicy?.minTTL||0,DefaultTTL:t.cachePolicy?.defaultTTL||86400,MaxTTL:t.cachePolicy?.maxTTL||31536000};if(t.edgeFunctions&&t.edgeFunctions.length>0)i.LambdaFunctionAssociations=t.edgeFunctions.map((a)=>({EventType:a.eventType,LambdaFunctionARN:a.functionArn}));let s={Enabled:!0,HttpVersion:t.http3?"http3":"http2",IPV6Enabled:!0,Origins:n,DefaultCacheBehavior:i,PriceClass:t.priceClass||"PriceClass_100",ViewerCertificate:{}};if(r.length>0)s.CacheBehaviors=r;if(t.customDomain)s.Aliases=[t.customDomain.domain],s.ViewerCertificate={AcmCertificateArn:t.customDomain.certificateArn,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else s.ViewerCertificate={CloudFrontDefaultCertificate:!0};if(t.errorPages)s.CustomErrorResponses=Object.entries(t.errorPages).map(([a,o])=>({ErrorCode:Number.parseInt(a),ResponseCode:200,ResponsePagePath:o,ErrorCachingMinTTL:300}));if(s.DefaultRootObject="index.html",s.Comment=d.sub("${AWS::StackName} CloudFront Distribution"),e.addResource("CloudFrontDistribution","AWS::CloudFront::Distribution",{DistributionConfig:s},{dependsOn:"CloudFrontOriginAccessIdentity"}),!t.origins||t.origins.length===0)e.addResource("StaticBucketPolicyForCloudFront","AWS::S3::BucketPolicy",{Bucket:d.ref("StaticBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontAccess",Effect:"Allow",Principal:{CanonicalUser:d.getAtt("CloudFrontOriginAccessIdentity","S3CanonicalUserId")},Action:"s3:GetObject",Resource:d.join("",[d.getAtt("StaticBucket","Arn"),"/*"])}]}},{dependsOn:["StaticBucket","CloudFrontOriginAccessIdentity"]});if(t.customDomain)e.addResource("CloudFrontDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:d.sub(`${Va(t.customDomain.domain)}.`),Name:t.customDomain.domain,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:d.getAtt("CloudFrontDistribution","DomainName"),EvaluateTargetHealth:!1}},{dependsOn:"CloudFrontDistribution"});if(e.addOutputs({CloudFrontDistributionId:{Description:"CloudFront distribution ID",Value:d.ref("CloudFrontDistribution"),Export:{Name:d.sub("${AWS::StackName}-cloudfront-id")}},CloudFrontDomainName:{Description:"CloudFront distribution domain name",Value:d.getAtt("CloudFrontDistribution","DomainName"),Export:{Name:d.sub("${AWS::StackName}-cloudfront-domain")}}}),t.customDomain)e.addOutputs({CloudFrontURL:{Description:"CloudFront custom domain URL",Value:d.sub(`https://${t.customDomain.domain}`)}})}function Va(e){let t=e.split(".");if(t.length>=2)return t.slice(-2).join(".");return e}function Tr(e,t){if(t.server)Ua(e,t.server);if(t.fargate)vr(e,"app",t.fargate);if(t.services)t.services.forEach((n)=>{if(n.type==="fargate")vr(e,n.name,{taskDefinition:n.taskDefinition,service:n.service})})}function Ua(e,t){if(!t)return;e.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for application instances",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:3000,ToPort:3000,SourceSecurityGroupId:d.ref("ALBSecurityGroup")},{IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:"0.0.0.0/0"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-app-sg")}]},{dependsOn:"VPC"}),e.addResource("EC2InstanceRole","AWS::IAM::Role",{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"],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-ec2-role")}]}),e.addResource("EC2InstanceProfile","AWS::IAM::InstanceProfile",{Roles:[d.ref("EC2InstanceRole")]},{dependsOn:"EC2InstanceRole"});let n=t.userData||`#!/bin/bash
2446
2446
  set -e
2447
2447
  # Update system
2448
2448
  yum update -y || apt-get update -y
@@ -2460,17 +2460,17 @@ rpm -U ./amazon-cloudwatch-agent.rpm || true
2460
2460
  `;if(e.addResource("LaunchTemplate","AWS::EC2::LaunchTemplate",{LaunchTemplateName:d.sub("${AWS::StackName}-template"),LaunchTemplateData:{ImageId:t.ami||d.findInMap("RegionMap",d.ref("AWS::Region"),"AMI"),InstanceType:t.instanceType,IamInstanceProfile:{Arn:d.getAtt("EC2InstanceProfile","Arn")},SecurityGroupIds:[d.ref("AppSecurityGroup")],UserData:d.base64(d.sub(n)),TagSpecifications:[{ResourceType:"instance",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-instance")}]}],MetadataOptions:{HttpTokens:"required",HttpPutResponseHopLimit:1}}},{dependsOn:["AppSecurityGroup","EC2InstanceProfile"]}),t.loadBalancer){Ha(e,t.loadBalancer);let r={LaunchTemplate:{LaunchTemplateId:d.ref("LaunchTemplate"),Version:d.getAtt("LaunchTemplate","LatestVersionNumber")},MinSize:t.autoScaling?.min.toString()||"1",MaxSize:t.autoScaling?.max.toString()||"3",DesiredCapacity:t.autoScaling?.min.toString()||"2",VPCZoneIdentifier:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],TargetGroupARNs:[d.ref("TargetGroup")],HealthCheckType:"ELB",HealthCheckGracePeriod:300,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-asg"),PropagateAtLaunch:!0}]};if(e.addResource("AutoScalingGroup","AWS::AutoScaling::AutoScalingGroup",r,{dependsOn:["LaunchTemplate","TargetGroup"]}),t.autoScaling)e.addResource("ScaleUpPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:d.ref("AutoScalingGroup"),Cooldown:t.autoScaling.scaleUpCooldown?.toString()||"300",ScalingAdjustment:"1"},{dependsOn:"AutoScalingGroup"}),e.addResource("ScaleDownPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:d.ref("AutoScalingGroup"),Cooldown:t.autoScaling.scaleDownCooldown?.toString()||"300",ScalingAdjustment:"-1"},{dependsOn:"AutoScalingGroup"}),e.addResource("HighCPUAlarm","AWS::CloudWatch::Alarm",{AlarmDescription:"Scale up when CPU exceeds target",MetricName:"CPUUtilization",Namespace:"AWS/EC2",Statistic:"Average",Period:"300",EvaluationPeriods:"2",Threshold:(t.autoScaling.targetCPU||70).toString(),AlarmActions:[d.ref("ScaleUpPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:d.ref("AutoScalingGroup")}],ComparisonOperator:"GreaterThanThreshold"},{dependsOn:["AutoScalingGroup","ScaleUpPolicy"]}),e.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:((t.autoScaling.targetCPU||70)-20).toString(),AlarmActions:[d.ref("ScaleDownPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:d.ref("AutoScalingGroup")}],ComparisonOperator:"LessThanThreshold"},{dependsOn:["AutoScalingGroup","ScaleDownPolicy"]})}}function Ha(e,t){if(!t)return;e.addResource("ALBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for Application Load Balancer",VpcId:d.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:d.sub("${AWS::StackName}-alb-sg")}]},{dependsOn:"VPC"}),e.addResource("LoadBalancer","AWS::ElasticLoadBalancingV2::LoadBalancer",{Name:d.sub("${AWS::StackName}-alb"),Type:t.type||"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[d.ref("PublicSubnet1"),d.ref("PublicSubnet2")],SecurityGroups:[d.ref("ALBSecurityGroup")],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-alb")}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]}),e.addResource("TargetGroup","AWS::ElasticLoadBalancingV2::TargetGroup",{Name:d.sub("${AWS::StackName}-tg"),Port:3000,Protocol:"HTTP",VpcId:d.ref("VPC"),HealthCheckEnabled:!0,HealthCheckPath:t.healthCheck?.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:t.healthCheck?.interval||30,HealthCheckTimeoutSeconds:t.healthCheck?.timeout||5,HealthyThresholdCount:t.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:t.healthCheck?.unhealthyThreshold||3,TargetType:"instance",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-tg")}]},{dependsOn:"VPC"}),e.addResource("LoadBalancerListener","AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:d.ref("LoadBalancer"),Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:d.ref("TargetGroup")}]},{dependsOn:["LoadBalancer","TargetGroup"]}),e.addOutputs({LoadBalancerDNS:{Description:"Load Balancer DNS Name",Value:d.getAtt("LoadBalancer","DNSName"),Export:{Name:d.sub("${AWS::StackName}-alb-dns")}}})}function vr(e,t,n){let r=e.toLogicalId(t),i=n.taskDefinition.containerDefinitions?.[0],s=i?.name||i?.Name||t,a=i?.portMappings?.[0]?.containerPort||i?.PortMappings?.[0]?.ContainerPort||3000,o=(n.taskDefinition.containerDefinitions||[]).flatMap((p)=>(p.secrets||p.Secrets||[]).map((g)=>g.valueFrom||g.ValueFrom)).filter(Boolean);if(!e.hasResource("ECSCluster"))e.addResource("ECSCluster","AWS::ECS::Cluster",{ClusterName:d.sub("${AWS::StackName}-cluster"),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cluster")}]});if(e.addResource(`${r}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"],...o.length?{Policies:[{PolicyName:"read-task-secrets",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameters"],Resource:o},{Effect:"Allow",Action:"kms:Decrypt",Resource:"*"}]}}]}:{}}),e.addResource(`${r}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:d.sub("arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:${AWS::StackName}-*")},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:"*"}]}}]}),!e.hasResource("ALBSecurityGroup"))e.addResource("ALBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Public ingress for the application load balancer",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0"},...n.loadBalancer?.customDomain?.certificateArn?[{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0"}]:[]],SecurityGroupEgress:[{IpProtocol:"tcp",FromPort:a,ToPort:a,CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-alb-sg")}]},{dependsOn:"VPC"});if(!e.hasResource("AppSecurityGroup"))e.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Only the application load balancer may reach Fargate tasks",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:a,ToPort:a,SourceSecurityGroupId:d.ref("ALBSecurityGroup")}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-app-sg")}]},{dependsOn:["VPC","ALBSecurityGroup"]});let c=(n.taskDefinition.containerDefinitions||[{name:t,image:d.sub(`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${t}:latest`),portMappings:[{containerPort:3000}]}]).map((p)=>({Name:p.Name||p.name,Image:p.Image||p.image,Essential:p.Essential??p.essential??!0,PortMappings:(p.PortMappings||p.portMappings||[]).map((g)=>({ContainerPort:g.ContainerPort??g.containerPort,Protocol:g.Protocol||g.protocol||"tcp"})),Environment:Array.isArray(p.Environment||p.environment)?(p.Environment||p.environment).map((g)=>({Name:g.Name||g.name,Value:g.Value??g.value})):Object.entries(p.Environment||p.environment||{}).map(([g,y])=>({Name:g,Value:y})),Secrets:(p.Secrets||p.secrets||[]).map((g)=>({Name:g.Name||g.name,ValueFrom:g.ValueFrom||g.valueFrom})),HealthCheck:p.HealthCheck||p.healthCheck,Command:p.Command||p.command,EntryPoint:p.EntryPoint||p.entryPoint,LogConfiguration:p.LogConfiguration||p.logConfiguration||{LogDriver:"awslogs",Options:{"awslogs-group":d.ref(`${r}LogGroup`),"awslogs-region":d.ref("AWS::Region"),"awslogs-stream-prefix":t}}}));e.addResource(`${r}TaskDefinition`,"AWS::ECS::TaskDefinition",{Family:d.sub(`\${AWS::StackName}-${t}`),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:n.taskDefinition.cpu,Memory:n.taskDefinition.memory,ExecutionRoleArn:d.getAtt(`${r}TaskExecutionRole`,"Arn"),TaskRoleArn:d.getAtt(`${r}TaskRole`,"Arn"),ContainerDefinitions:c},{dependsOn:[`${r}TaskExecutionRole`,`${r}TaskRole`,`${r}LogGroup`]}),e.addResource(`${r}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:d.sub(`/ecs/\${AWS::StackName}/${t}`),RetentionInDays:14});let l=n.service.healthCheck||{};e.addResource(`${r}TargetGroup`,"AWS::ElasticLoadBalancingV2::TargetGroup",{VpcId:d.ref("VPC"),Port:a,Protocol:"HTTP",TargetType:"ip",HealthCheckEnabled:!0,HealthCheckPath:l.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:l.interval||30,HealthCheckTimeoutSeconds:l.timeout||5,HealthyThresholdCount:l.healthyThreshold||2,UnhealthyThresholdCount:l.unhealthyThreshold||3,Matcher:{HttpCode:"200-399"},TargetGroupAttributes:[{Key:"deregistration_delay.timeout_seconds",Value:"30"}]},{dependsOn:"VPC"}),e.addResource(`${r}LoadBalancer`,"AWS::ElasticLoadBalancingV2::LoadBalancer",{Type:"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[d.ref("PublicSubnet1"),d.ref("PublicSubnet2")],SecurityGroups:[d.ref("ALBSecurityGroup")],LoadBalancerAttributes:[{Key:"routing.http.drop_invalid_header_fields.enabled",Value:"true"},{Key:"deletion_protection.enabled",Value:String(n.loadBalancer?.deletionProtection===!0)}],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}-alb`)}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]});let u=n.loadBalancer?.customDomain?.certificateArn,m=n.loadBalancer?.originVerifyHeader;if(e.addResource(`${r}HttpListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:d.ref(`${r}LoadBalancer`),Port:80,Protocol:"HTTP",DefaultActions:u?[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]:m?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:d.ref(`${r}TargetGroup`)}]},{dependsOn:[`${r}LoadBalancer`,`${r}TargetGroup`]}),u)e.addResource(`${r}HttpsListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:d.ref(`${r}LoadBalancer`),Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:u}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06",DefaultActions:m?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:d.ref(`${r}TargetGroup`)}]},{dependsOn:[`${r}LoadBalancer`,`${r}TargetGroup`]});if(m){let p=u?`${r}HttpsListener`:`${r}HttpListener`;e.addResource(`${r}OriginVerifyRule`,"AWS::ElasticLoadBalancingV2::ListenerRule",{ListenerArn:d.ref(p),Priority:1,Conditions:[{Field:"http-header",HttpHeaderConfig:{HttpHeaderName:m.name,Values:[m.value]}}],Actions:[{Type:"forward",TargetGroupArn:d.ref(`${r}TargetGroup`)}]},{dependsOn:[p,`${r}TargetGroup`]})}if(e.addResource(`${r}Service`,"AWS::ECS::Service",{ServiceName:d.sub(`\${AWS::StackName}-${t}`),Cluster:d.ref("ECSCluster"),TaskDefinition:d.ref(`${r}TaskDefinition`),DesiredCount:n.service.desiredCount,LaunchType:"FARGATE",PlatformVersion:"LATEST",HealthCheckGracePeriodSeconds:60,DeploymentConfiguration:{MinimumHealthyPercent:100,MaximumPercent:200,DeploymentCircuitBreaker:{Enable:!0,Rollback:!0}},LoadBalancers:[{ContainerName:s,ContainerPort:a,TargetGroupArn:d.ref(`${r}TargetGroup`)}],NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"DISABLED",Subnets:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],SecurityGroups:[d.ref("AppSecurityGroup")]}}},{dependsOn:["ECSCluster",`${r}TaskDefinition`,m?`${r}OriginVerifyRule`:u?`${r}HttpsListener`:`${r}HttpListener`]}),n.service.autoScaling){let p=n.service.autoScaling;e.addResource(`${r}ScalableTarget`,"AWS::ApplicationAutoScaling::ScalableTarget",{MinCapacity:p.min,MaxCapacity:p.max,ResourceId:d.join("/",["service",d.ref("ECSCluster"),d.getAtt(`${r}Service`,"Name")]),RoleARN:d.sub("arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"),ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs"},{dependsOn:`${r}Service`}),e.addResource(`${r}ScalingPolicy`,"AWS::ApplicationAutoScaling::ScalingPolicy",{PolicyType:"TargetTrackingScaling",ScalingTargetId:d.ref(`${r}ScalableTarget`),TargetTrackingScalingPolicyConfiguration:{TargetValue:p.targetCPU||70,PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},ScaleInCooldown:60,ScaleOutCooldown:30}},{dependsOn:`${r}ScalableTarget`})}e.addOutputs({[`${r}ClusterName`]:{Description:"ECS cluster name",Value:d.ref("ECSCluster")},[`${r}ServiceName`]:{Description:"ECS service name",Value:d.getAtt(`${r}Service`,"Name")},[`${r}LoadBalancerDnsName`]:{Description:"ALB origin hostname",Value:d.getAtt(`${r}LoadBalancer`,"DNSName")},[`${r}LoadBalancerHostedZoneId`]:{Description:"ALB canonical hosted zone ID",Value:d.getAtt(`${r}LoadBalancer`,"CanonicalHostedZoneID")},[`${r}TargetGroupArn`]:{Description:"ECS target group ARN",Value:d.ref(`${r}TargetGroup`)}})}function Pr(e,t){if(t.postgres)Rr(e,"postgres",t.postgres);if(t.mysql)Rr(e,"mysql",t.mysql);if(t.dynamodb?.tables)t.dynamodb.tables.forEach((n)=>{ja(e,n)})}function Rr(e,t,n){if(!n)return;let r=t==="postgres"?"postgres":"mysql",i=e.toLogicalId(`${r}-db`);e.addResource("DBSubnetGroup","AWS::RDS::DBSubnetGroup",{DBSubnetGroupDescription:"Subnet group for RDS instance",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-db-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("DBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for RDS instance",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:t==="postgres"?5432:3306,ToPort:t==="postgres"?5432:3306,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-db-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});let s=t==="postgres"?`postgres${n.version.split(".")[0]}`:`mysql${n.version.split(".")[0]}.${n.version.split(".")[1]||"0"}`;if(n.parameters&&Object.keys(n.parameters).length>0)e.addResource("DBParameterGroup","AWS::RDS::DBParameterGroup",{Description:`Parameter group for ${r}`,Family:s,Parameters:n.parameters,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-db-params")}]});e.addResource("DBSecret","AWS::SecretsManager::Secret",{Description:"Database credentials",GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"admin"}),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\'},Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-db-secret")}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"});let a={Engine:r,EngineVersion:n.version,DBInstanceClass:n.instanceClass,AllocatedStorage:n.allocatedStorage.toString(),MaxAllocatedStorage:n.maxAllocatedStorage?.toString(),StorageType:"gp3",StorageEncrypted:!0,MultiAZ:n.multiAZ!==!1,DBSubnetGroupName:d.ref("DBSubnetGroup"),VPCSecurityGroups:[d.ref("DBSecurityGroup")],MasterUsername:d.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:username}}"),MasterUserPassword:d.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:password}}"),BackupRetentionPeriod:n.backupRetentionDays||7,PreferredBackupWindow:n.preferredBackupWindow||"03:00-04:00",PreferredMaintenanceWindow:n.preferredMaintenanceWindow||"sun:04:00-sun:05:00",EnablePerformanceInsights:n.enablePerformanceInsights!==!1,PerformanceInsightsRetentionPeriod:n.performanceInsightsRetention||7,DeletionProtection:n.deletionProtection!==!1,CopyTagsToSnapshot:!0,EnableCloudwatchLogsExports:t==="postgres"?["postgresql"]:["error","general","slowquery"],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${r}-db`)}]};if(n.parameters&&Object.keys(n.parameters).length>0)a.DBParameterGroupName=d.ref("DBParameterGroup");e.addResource(i,"AWS::RDS::DBInstance",a,{dependsOn:["DBSubnetGroup","DBSecurityGroup","DBSecret"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addResource("DBSecretAttachment","AWS::SecretsManager::SecretTargetAttachment",{SecretId:d.ref("DBSecret"),TargetId:d.ref(i),TargetType:"AWS::RDS::DBInstance"},{dependsOn:[i,"DBSecret"]}),e.addOutputs({DBEndpoint:{Description:"Database endpoint",Value:d.getAtt(i,"Endpoint.Address"),Export:{Name:d.sub("${AWS::StackName}-db-endpoint")}},DBPort:{Description:"Database port",Value:d.getAtt(i,"Endpoint.Port"),Export:{Name:d.sub("${AWS::StackName}-db-port")}},DBSecretArn:{Description:"ARN of the database credentials secret",Value:d.ref("DBSecret"),Export:{Name:d.sub("${AWS::StackName}-db-secret-arn")}}})}function ja(e,t){let n=e.toLogicalId(`${t.name}-table`),r={TableName:d.sub(`\${AWS::StackName}-${t.name}`),BillingMode:t.billingMode||"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:t.partitionKey,AttributeType:"S"}],KeySchema:[{AttributeName:t.partitionKey,KeyType:"HASH"}],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}`)}]};if(t.sortKey)r.AttributeDefinitions.push({AttributeName:t.sortKey,AttributeType:"S"}),r.KeySchema.push({AttributeName:t.sortKey,KeyType:"RANGE"});if(t.billingMode==="PROVISIONED")r.ProvisionedThroughput={ReadCapacityUnits:t.readCapacity||5,WriteCapacityUnits:t.writeCapacity||5};if(t.streamEnabled)r.StreamSpecification={StreamViewType:"NEW_AND_OLD_IMAGES"};if(t.pointInTimeRecovery)r.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(t.ttl?.enabled)r.TimeToLiveSpecification={Enabled:!0,AttributeName:t.ttl.attributeName};if(t.globalSecondaryIndexes&&t.globalSecondaryIndexes.length>0)r.GlobalSecondaryIndexes=t.globalSecondaryIndexes.map((i)=>{let s=new Set(r.AttributeDefinitions.map((o)=>o.AttributeName));if(!s.has(i.partitionKey))r.AttributeDefinitions.push({AttributeName:i.partitionKey,AttributeType:"S"});if(i.sortKey&&!s.has(i.sortKey))r.AttributeDefinitions.push({AttributeName:i.sortKey,AttributeType:"S"});let a={IndexName:i.name,KeySchema:[{AttributeName:i.partitionKey,KeyType:"HASH"}],Projection:{ProjectionType:i.projectionType||"ALL"}};if(i.sortKey)a.KeySchema.push({AttributeName:i.sortKey,KeyType:"RANGE"});if(i.projectionType==="INCLUDE"&&i.nonKeyAttributes)a.Projection.NonKeyAttributes=i.nonKeyAttributes;if(t.billingMode==="PROVISIONED")a.ProvisionedThroughput={ReadCapacityUnits:t.readCapacity||5,WriteCapacityUnits:t.writeCapacity||5};return a});if(e.addResource(n,"AWS::DynamoDB::Table",r,{deletionPolicy:"Retain"}),e.addOutputs({[`${n}Name`]:{Description:`${t.name} table name`,Value:d.ref(n),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-table`)}},[`${n}Arn`]:{Description:`${t.name} table ARN`,Value:d.getAtt(n,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-table-arn`)}}}),t.streamEnabled)e.addOutputs({[`${n}StreamArn`]:{Description:`${t.name} stream ARN`,Value:d.getAtt(n,"StreamArn"),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-stream-arn`)}}})}function Er(e,t){for(let[n,r]of Object.entries(t))r.forEach((i)=>{Ka(e,i,n)})}function Ka(e,t,n){let r=e.toLogicalId(`${n}-${t.name}-function`),i=`${r}Role`;e.addResource(i,"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:[...za(t.events||[])]}}],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}-role`)}]});let s={FunctionName:d.sub(`\${AWS::StackName}-${t.name}`),Runtime:t.runtime,Handler:t.handler,Role:d.getAtt(i,"Arn"),MemorySize:t.memory,Timeout:t.timeout,Code:{ZipFile:`exports.handler = async (event) => {
2461
2461
  console.log('Event:', JSON.stringify(event, null, 2));
2462
2462
  return { statusCode: 200, body: 'Function not yet implemented' };
2463
- };`},Environment:t.environment?{Variables:t.environment}:void 0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}`)}]};if(n!=="edge")s.VpcConfig={SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],SecurityGroupIds:[d.ref("AppSecurityGroup")]};if(e.addResource(r,"AWS::Lambda::Function",s,{dependsOn:i}),e.addResource(`${r}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:d.sub(`/aws/lambda/\${AWS::StackName}-${t.name}`),RetentionInDays:14}),t.events)t.events.forEach((a,o)=>{qa(e,r,a,o)});e.addOutputs({[`${r}Arn`]:{Description:`${t.name} function ARN`,Value:d.getAtt(r,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-function-arn`)}}})}function qa(e,t,n,r){let i=`${t}EventSource${r}`;switch(n.type){case"http":break;case"s3":if(n.bucket){let s=e.toLogicalId(`${n.bucket}-bucket`);e.addResource(`${i}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(t),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:Fe.s3Bucket(d.ref(s))},{dependsOn:[t,s]})}break;case"sqs":if(n.queueName){let s=e.toLogicalId(`${n.queueName}-queue`);e.addResource(i,"AWS::Lambda::EventSourceMapping",{EventSourceArn:d.getAtt(s,"Arn"),FunctionName:d.ref(t),BatchSize:n.batchSize||10},{dependsOn:[t,s]})}break;case"kinesis":if(n.streamName){let s=e.toLogicalId(`${n.streamName}-stream`);e.addResource(i,"AWS::Lambda::EventSourceMapping",{EventSourceArn:d.getAtt(s,"Arn"),FunctionName:d.ref(t),BatchSize:n.batchSize||100,StartingPosition:n.startingPosition||"LATEST",ParallelizationFactor:n.parallelizationFactor||1},{dependsOn:[t,s]})}break;case"dynamodb-stream":if(n.tableName){let s=e.toLogicalId(`${n.tableName}-table`);e.addResource(i,"AWS::Lambda::EventSourceMapping",{EventSourceArn:d.getAtt(s,"StreamArn"),FunctionName:d.ref(t),BatchSize:n.batchSize||100,StartingPosition:n.startingPosition||"LATEST"},{dependsOn:[t,s]})}break;case"schedule":if(n.expression)e.addResource(`${i}Rule`,"AWS::Events::Rule",{ScheduleExpression:n.expression,State:"ENABLED",Targets:[{Arn:d.getAtt(t,"Arn"),Id:`${t}Target`}]},{dependsOn:t}),e.addResource(`${i}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(t),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:d.getAtt(`${i}Rule`,"Arn")},{dependsOn:[t,`${i}Rule`]});break}}function za(e){let t=[];if(!e)return t;if(e.forEach((n)=>{switch(n.type){case"s3":t.push({Effect:"Allow",Action:["s3:GetObject","s3:GetObjectVersion"],Resource:n.bucket?`arn:aws:s3:::${n.bucket}/*`:"arn:aws:s3:::*/*"});break;case"sqs":t.push({Effect:"Allow",Action:["sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes"],Resource:n.queueName?Fe.sqs(n.queueName):"arn:aws:sqs:*:*:*"});break;case"kinesis":t.push({Effect:"Allow",Action:["kinesis:GetRecords","kinesis:GetShardIterator","kinesis:DescribeStream","kinesis:ListStreams"],Resource:n.streamName?Fe.kinesis(n.streamName):"arn:aws:kinesis:*:*:stream/*"});break;case"dynamodb-stream":t.push({Effect:"Allow",Action:["dynamodb:GetRecords","dynamodb:GetShardIterator","dynamodb:DescribeStream","dynamodb:ListStreams"],Resource:n.tableName?d.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${n.tableName}/stream/*`):"arn:aws:dynamodb:*:*:table/*/stream/*"});break}}),t.length===0)t.push({Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:*"});return t}function wr(e,t){if(t.topics)t.topics.forEach((n)=>{Qa(e,n)})}function Qa(e,t){let n=e.toLogicalId(`${t.name}-topic`);if(e.addResource(n,"AWS::SNS::Topic",{TopicName:d.sub(`\${AWS::StackName}-${t.name}`),DisplayName:t.displayName||t.name,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}`)}]}),e.addResource(`${n}Policy`,"AWS::SNS::TopicPolicy",{Topics:[d.ref(n)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["events.amazonaws.com","cloudwatch.amazonaws.com","s3.amazonaws.com"]},Action:"sns:Publish",Resource:d.ref(n)},{Effect:"Allow",Principal:{AWS:d.sub("arn:aws:iam::${AWS::AccountId}:root")},Action:["sns:Subscribe","sns:Publish","sns:Receive"],Resource:d.ref(n)}]}},{dependsOn:n}),t.subscriptions)t.subscriptions.forEach((r,i)=>{let s=`${n}Subscription${i+1}`,a={Protocol:r.protocol,TopicArn:d.ref(n),Endpoint:r.endpoint};if(r.filterPolicy)a.FilterPolicy=r.filterPolicy;if(r.protocol==="sqs"){let o=e.toLogicalId(`${r.endpoint}-queue`);a.Endpoint=d.getAtt(o,"Arn")}if(r.protocol==="lambda"){let o=e.toLogicalId(r.endpoint);a.Endpoint=d.getAtt(o,"Arn"),e.addResource(`${s}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(o),Action:"lambda:InvokeFunction",Principal:"sns.amazonaws.com",SourceArn:d.ref(n)},{dependsOn:[o,n]})}e.addResource(s,"AWS::SNS::Subscription",a,{dependsOn:n})});e.addOutputs({[`${n}Arn`]:{Description:`${t.name} topic ARN`,Value:d.ref(n),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-topic-arn`)}}})}function Ir(e,t){if(t.alarms&&t.alarms.length>0)e.addResource("AlarmTopic","AWS::SNS::Topic",{TopicName:d.sub("${AWS::StackName}-alarms"),DisplayName:"CloudWatch Alarms",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-alarms")}]}),t.alarms.forEach((n,r)=>{Ja(e,n,r)});if(t.dashboard)Ya(e,t.dashboard);if(t.logs?.groups)t.logs.groups.forEach((n)=>{Za(e,n,t.logs?.retention)})}function Ja(e,t,n){let r=e.toLogicalId(`alarm-${t.name||t.metric}-${n}`),i={AlarmName:t.name||d.sub(`\${AWS::StackName}-${t.metric}`),AlarmDescription:`Alarm for ${t.metric}`,MetricName:t.metric,Namespace:t.namespace||Yt(t.metric,t.service),Statistic:t.statistic||"Average",Period:t.period||300,EvaluationPeriods:t.evaluationPeriods||1,Threshold:t.threshold,ComparisonOperator:t.comparisonOperator||"GreaterThanThreshold",TreatMissingData:t.treatMissingData||"notBreaching",AlarmActions:[d.ref("AlarmTopic")],OKActions:[d.ref("AlarmTopic")]};if(t.dimensions)i.Dimensions=Object.entries(t.dimensions).map(([s,a])=>({Name:s,Value:a}));else if(t.service)i.Dimensions=Xa(t.service);e.addResource(r,"AWS::CloudWatch::Alarm",i,{dependsOn:"AlarmTopic"})}function Ya(e,t){if(!t)return;let n=[],r=0,i=0;t.widgets?.forEach((s)=>{let a=s.width||12,o=s.height||6;if(s.type==="metric"&&s.metrics){let c=s.metrics.map((l)=>{if(typeof l==="string")return[Yt(l),l];else return[Yt(l.metric,l.service),l.metric]});n.push({type:"metric",x:r,y:i,width:a,height:o,properties:{metrics:c,period:300,stat:"Average",region:d.ref("AWS::Region"),title:s.metrics.length>1?"Multiple Metrics":typeof s.metrics[0]==="string"?s.metrics[0]:s.metrics[0].metric}})}else if(s.type==="log"&&s.logGroup)n.push({type:"log",x:r,y:i,width:a,height:o,properties:{query:`SOURCE '${s.logGroup}'
2463
+ };`},Environment:t.environment?{Variables:t.environment}:void 0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}`)}]};if(n!=="edge")s.VpcConfig={SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],SecurityGroupIds:[d.ref("AppSecurityGroup")]};if(e.addResource(r,"AWS::Lambda::Function",s,{dependsOn:i}),e.addResource(`${r}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:d.sub(`/aws/lambda/\${AWS::StackName}-${t.name}`),RetentionInDays:14}),t.events)t.events.forEach((a,o)=>{qa(e,r,a,o)});e.addOutputs({[`${r}Arn`]:{Description:`${t.name} function ARN`,Value:d.getAtt(r,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-function-arn`)}}})}function qa(e,t,n,r){let i=`${t}EventSource${r}`;switch(n.type){case"http":break;case"s3":if(n.bucket){let s=e.toLogicalId(`${n.bucket}-bucket`);e.addResource(`${i}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(t),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:_e.s3Bucket(d.ref(s))},{dependsOn:[t,s]})}break;case"sqs":if(n.queueName){let s=e.toLogicalId(`${n.queueName}-queue`);e.addResource(i,"AWS::Lambda::EventSourceMapping",{EventSourceArn:d.getAtt(s,"Arn"),FunctionName:d.ref(t),BatchSize:n.batchSize||10},{dependsOn:[t,s]})}break;case"kinesis":if(n.streamName){let s=e.toLogicalId(`${n.streamName}-stream`);e.addResource(i,"AWS::Lambda::EventSourceMapping",{EventSourceArn:d.getAtt(s,"Arn"),FunctionName:d.ref(t),BatchSize:n.batchSize||100,StartingPosition:n.startingPosition||"LATEST",ParallelizationFactor:n.parallelizationFactor||1},{dependsOn:[t,s]})}break;case"dynamodb-stream":if(n.tableName){let s=e.toLogicalId(`${n.tableName}-table`);e.addResource(i,"AWS::Lambda::EventSourceMapping",{EventSourceArn:d.getAtt(s,"StreamArn"),FunctionName:d.ref(t),BatchSize:n.batchSize||100,StartingPosition:n.startingPosition||"LATEST"},{dependsOn:[t,s]})}break;case"schedule":if(n.expression)e.addResource(`${i}Rule`,"AWS::Events::Rule",{ScheduleExpression:n.expression,State:"ENABLED",Targets:[{Arn:d.getAtt(t,"Arn"),Id:`${t}Target`}]},{dependsOn:t}),e.addResource(`${i}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(t),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:d.getAtt(`${i}Rule`,"Arn")},{dependsOn:[t,`${i}Rule`]});break}}function za(e){let t=[];if(!e)return t;if(e.forEach((n)=>{switch(n.type){case"s3":t.push({Effect:"Allow",Action:["s3:GetObject","s3:GetObjectVersion"],Resource:n.bucket?`arn:aws:s3:::${n.bucket}/*`:"arn:aws:s3:::*/*"});break;case"sqs":t.push({Effect:"Allow",Action:["sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes"],Resource:n.queueName?_e.sqs(n.queueName):"arn:aws:sqs:*:*:*"});break;case"kinesis":t.push({Effect:"Allow",Action:["kinesis:GetRecords","kinesis:GetShardIterator","kinesis:DescribeStream","kinesis:ListStreams"],Resource:n.streamName?_e.kinesis(n.streamName):"arn:aws:kinesis:*:*:stream/*"});break;case"dynamodb-stream":t.push({Effect:"Allow",Action:["dynamodb:GetRecords","dynamodb:GetShardIterator","dynamodb:DescribeStream","dynamodb:ListStreams"],Resource:n.tableName?d.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${n.tableName}/stream/*`):"arn:aws:dynamodb:*:*:table/*/stream/*"});break}}),t.length===0)t.push({Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:*"});return t}function wr(e,t){if(t.topics)t.topics.forEach((n)=>{Qa(e,n)})}function Qa(e,t){let n=e.toLogicalId(`${t.name}-topic`);if(e.addResource(n,"AWS::SNS::Topic",{TopicName:d.sub(`\${AWS::StackName}-${t.name}`),DisplayName:t.displayName||t.name,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}`)}]}),e.addResource(`${n}Policy`,"AWS::SNS::TopicPolicy",{Topics:[d.ref(n)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["events.amazonaws.com","cloudwatch.amazonaws.com","s3.amazonaws.com"]},Action:"sns:Publish",Resource:d.ref(n)},{Effect:"Allow",Principal:{AWS:d.sub("arn:aws:iam::${AWS::AccountId}:root")},Action:["sns:Subscribe","sns:Publish","sns:Receive"],Resource:d.ref(n)}]}},{dependsOn:n}),t.subscriptions)t.subscriptions.forEach((r,i)=>{let s=`${n}Subscription${i+1}`,a={Protocol:r.protocol,TopicArn:d.ref(n),Endpoint:r.endpoint};if(r.filterPolicy)a.FilterPolicy=r.filterPolicy;if(r.protocol==="sqs"){let o=e.toLogicalId(`${r.endpoint}-queue`);a.Endpoint=d.getAtt(o,"Arn")}if(r.protocol==="lambda"){let o=e.toLogicalId(r.endpoint);a.Endpoint=d.getAtt(o,"Arn"),e.addResource(`${s}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(o),Action:"lambda:InvokeFunction",Principal:"sns.amazonaws.com",SourceArn:d.ref(n)},{dependsOn:[o,n]})}e.addResource(s,"AWS::SNS::Subscription",a,{dependsOn:n})});e.addOutputs({[`${n}Arn`]:{Description:`${t.name} topic ARN`,Value:d.ref(n),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-topic-arn`)}}})}function Ir(e,t){if(t.alarms&&t.alarms.length>0)e.addResource("AlarmTopic","AWS::SNS::Topic",{TopicName:d.sub("${AWS::StackName}-alarms"),DisplayName:"CloudWatch Alarms",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-alarms")}]}),t.alarms.forEach((n,r)=>{Ja(e,n,r)});if(t.dashboard)Ya(e,t.dashboard);if(t.logs?.groups)t.logs.groups.forEach((n)=>{Za(e,n,t.logs?.retention)})}function Ja(e,t,n){let r=e.toLogicalId(`alarm-${t.name||t.metric}-${n}`),i={AlarmName:t.name||d.sub(`\${AWS::StackName}-${t.metric}`),AlarmDescription:`Alarm for ${t.metric}`,MetricName:t.metric,Namespace:t.namespace||Yt(t.metric,t.service),Statistic:t.statistic||"Average",Period:t.period||300,EvaluationPeriods:t.evaluationPeriods||1,Threshold:t.threshold,ComparisonOperator:t.comparisonOperator||"GreaterThanThreshold",TreatMissingData:t.treatMissingData||"notBreaching",AlarmActions:[d.ref("AlarmTopic")],OKActions:[d.ref("AlarmTopic")]};if(t.dimensions)i.Dimensions=Object.entries(t.dimensions).map(([s,a])=>({Name:s,Value:a}));else if(t.service)i.Dimensions=Xa(t.service);e.addResource(r,"AWS::CloudWatch::Alarm",i,{dependsOn:"AlarmTopic"})}function Ya(e,t){if(!t)return;let n=[],r=0,i=0;t.widgets?.forEach((s)=>{let a=s.width||12,o=s.height||6;if(s.type==="metric"&&s.metrics){let c=s.metrics.map((l)=>{if(typeof l==="string")return[Yt(l),l];else return[Yt(l.metric,l.service),l.metric]});n.push({type:"metric",x:r,y:i,width:a,height:o,properties:{metrics:c,period:300,stat:"Average",region:d.ref("AWS::Region"),title:s.metrics.length>1?"Multiple Metrics":typeof s.metrics[0]==="string"?s.metrics[0]:s.metrics[0].metric}})}else if(s.type==="log"&&s.logGroup)n.push({type:"log",x:r,y:i,width:a,height:o,properties:{query:`SOURCE '${s.logGroup}'
2464
2464
  | fields @timestamp, @message
2465
2465
  | sort @timestamp desc
2466
- | limit 20`,region:d.ref("AWS::Region"),title:`Logs: ${s.logGroup}`}});else if(s.type==="text"&&s.text)n.push({type:"text",x:r,y:i,width:a,height:o,properties:{markdown:s.text}});if(r+=a,r>=24)r=0,i+=o}),e.addResource("CloudWatchDashboard","AWS::CloudWatch::Dashboard",{DashboardName:d.sub(`\${AWS::StackName}-${t.name}`),DashboardBody:JSON.stringify({widgets:n})}),e.addOutputs({DashboardURL:{Description:"CloudWatch Dashboard URL",Value:d.sub("https://console.aws.amazon.com/cloudwatch/home?region=${AWS::Region}#dashboards:name=${CloudWatchDashboard}")}})}function Za(e,t,n){let r=e.toLogicalId(`${t}-log-group`);e.addResource(r,"AWS::Logs::LogGroup",{LogGroupName:d.sub(`/aws/\${AWS::StackName}/${t}`),RetentionInDays:n||14,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]})}function Yt(e,t){if(t)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"}[t.toLowerCase()]||"AWS/CloudWatch";let n=e.toLowerCase();if(n.includes("cpu")||n.includes("memory")||n.includes("network"))return"AWS/EC2";if(n.includes("lambda")||n.includes("invocation")||n.includes("duration"))return"AWS/Lambda";if(n.includes("request")||n.includes("latency")||n.includes("target"))return"AWS/ApplicationELB";if(n.includes("database")||n.includes("connection"))return"AWS/RDS";if(n.includes("read")||n.includes("write")||n.includes("consumed"))return"AWS/DynamoDB";return"AWS/CloudWatch"}function Xa(e){return{ec2:[{Name:"InstanceId",Value:d.ref("EC2Instance")}],ecs:[{Name:"ClusterName",Value:d.ref("ECSCluster")},{Name:"ServiceName",Value:d.getAtt("ECSService","Name")}],lambda:[{Name:"FunctionName",Value:d.ref("LambdaFunction")}],rds:[{Name:"DBInstanceIdentifier",Value:d.ref("Database")}],dynamodb:[{Name:"TableName",Value:d.ref("DynamoDBTable")}],alb:[{Name:"LoadBalancer",Value:d.getAtt("LoadBalancer","LoadBalancerFullName")}],apigateway:[{Name:"ApiName",Value:d.ref("HttpApi")}]}[e.toLowerCase()]||[]}function Dr(e,t){if(!t.vpc)return;let{cidr:n="10.0.0.0/16",availabilityZones:r=2,natGateways:i=1,enableDnsHostnames:s=!0,enableDnsSupport:a=!0}=t.vpc;e.addResource("VPC","AWS::EC2::VPC",{CidrBlock:n,EnableDnsHostnames:s,EnableDnsSupport:a,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-vpc")}]}),e.addResource("InternetGateway","AWS::EC2::InternetGateway",{Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-igw")}]}),e.addResource("VPCGatewayAttachment","AWS::EC2::VPCGatewayAttachment",{VpcId:d.ref("VPC"),InternetGatewayId:d.ref("InternetGateway")},{dependsOn:["VPC","InternetGateway"]});let o=[];for(let m=0;m<r;m++){let p=`PublicSubnet${m+1}`;o.push(p),e.addResource(p,"AWS::EC2::Subnet",{VpcId:d.ref("VPC"),CidrBlock:d.select(m,d.cidr(d.getAtt("VPC","CidrBlock"),r*2,8)),AvailabilityZone:d.select(m,d.getAZs()),MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-public-${m+1}`)},{Key:"Type",Value:"public"}]},{dependsOn:"VPC"})}let c=[];for(let m=0;m<r;m++){let p=`PrivateSubnet${m+1}`;c.push(p),e.addResource(p,"AWS::EC2::Subnet",{VpcId:d.ref("VPC"),CidrBlock:d.select(m+r,d.cidr(d.getAtt("VPC","CidrBlock"),r*2,8)),AvailabilityZone:d.select(m,d.getAZs()),MapPublicIpOnLaunch:!1,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-private-${m+1}`)},{Key:"Type",Value:"private"}]},{dependsOn:"VPC"})}let l=[];for(let m=0;m<i;m++){let p=`NatEIP${m+1}`;l.push(p),e.addResource(p,"AWS::EC2::EIP",{Domain:"vpc",Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-nat-eip-${m+1}`)}]},{dependsOn:"VPCGatewayAttachment"})}let u=[];for(let m=0;m<i;m++){let p=`NatGateway${m+1}`;u.push(p);let g=m%r;e.addResource(p,"AWS::EC2::NatGateway",{AllocationId:d.getAtt(l[m],"AllocationId"),SubnetId:d.ref(o[g]),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-nat-${m+1}`)}]},{dependsOn:[l[m],o[g]]})}e.addResource("PublicRouteTable","AWS::EC2::RouteTable",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-public-rt")}]},{dependsOn:"VPC"}),e.addResource("PublicRoute","AWS::EC2::Route",{RouteTableId:d.ref("PublicRouteTable"),DestinationCidrBlock:"0.0.0.0/0",GatewayId:d.ref("InternetGateway")},{dependsOn:["PublicRouteTable","VPCGatewayAttachment"]}),o.forEach((m,p)=>{e.addResource(`PublicSubnetRouteTableAssociation${p+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:d.ref(m),RouteTableId:d.ref("PublicRouteTable")},{dependsOn:[m,"PublicRouteTable"]})}),c.forEach((m,p)=>{let g=`PrivateRouteTable${p+1}`,y=p%i;e.addResource(g,"AWS::EC2::RouteTable",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-private-rt-${p+1}`)}]},{dependsOn:"VPC"}),e.addResource(`PrivateRoute${p+1}`,"AWS::EC2::Route",{RouteTableId:d.ref(g),DestinationCidrBlock:"0.0.0.0/0",NatGatewayId:d.ref(u[y])},{dependsOn:[g,u[y]]}),e.addResource(`PrivateSubnetRouteTableAssociation${p+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:d.ref(m),RouteTableId:d.ref(g)},{dependsOn:[m,g]})}),e.addResource("S3VPCEndpoint","AWS::EC2::VPCEndpoint",{VpcId:d.ref("VPC"),ServiceName:d.sub("com.amazonaws.${AWS::Region}.s3"),VpcEndpointType:"Gateway",RouteTableIds:[d.ref("PublicRouteTable"),...Array.from({length:r},(m,p)=>d.ref(`PrivateRouteTable${p+1}`))]},{dependsOn:"VPC"}),e.addResource("NetworkAcl","AWS::EC2::NetworkAcl",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-nacl")}]},{dependsOn:"VPC"}),e.addResource("NetworkAclEntryInbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:d.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),e.addResource("NetworkAclEntryOutbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:d.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,Egress:!0,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),e.addOutputs({VPCId:{Description:"VPC ID",Value:d.ref("VPC"),Export:{Name:d.sub("${AWS::StackName}-VPC")}},PublicSubnets:{Description:"Public subnet IDs",Value:d.join(",",o.map((m)=>d.ref(m))),Export:{Name:d.sub("${AWS::StackName}-PublicSubnets")}},PrivateSubnets:{Description:"Private subnet IDs",Value:d.join(",",c.map((m)=>d.ref(m))),Export:{Name:d.sub("${AWS::StackName}-PrivateSubnets")}}})}function Nr(e,t){for(let[n,r]of Object.entries(t))eo(e,n,r)}function eo(e,t,n){let r=e.toLogicalId(`${t}-queue`),i=n.fifo||!1,s;if(n.deadLetterQueue){let o=`${r}DLQ`;e.addResource(o,"AWS::SQS::Queue",{QueueName:i?d.sub(`\${AWS::StackName}-${t}-dlq.fifo`):d.sub(`\${AWS::StackName}-${t}-dlq`),FifoQueue:i,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}-dlq`)}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),s=d.getAtt(o,"Arn")}let a={QueueName:i?d.sub(`\${AWS::StackName}-${t}.fifo`):d.sub(`\${AWS::StackName}-${t}`),FifoQueue:i,VisibilityTimeout:n.visibilityTimeout||30,MessageRetentionPeriod:n.messageRetentionPeriod||345600,ReceiveMessageWaitTimeSeconds:n.receiveMessageWaitTime||0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]};if(i&&n.contentBasedDeduplication)a.ContentBasedDeduplication=!0;if(n.deadLetterQueue&&s)a.RedrivePolicy={deadLetterTargetArn:s,maxReceiveCount:n.maxReceiveCount||3};if(e.addResource(r,"AWS::SQS::Queue",a,{dependsOn:n.deadLetterQueue?`${r}DLQ`:void 0,deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),e.addResource(`${r}Policy`,"AWS::SQS::QueuePolicy",{Queues:[d.ref(r)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","events.amazonaws.com","sns.amazonaws.com"]},Action:"sqs:SendMessage",Resource:d.getAtt(r,"Arn"),Condition:{ArnEquals:{"aws:SourceArn":d.sub("arn:aws:*:${AWS::Region}:${AWS::AccountId}:*")}}}]}},{dependsOn:r}),e.addOutputs({[`${r}Url`]:{Description:`${t} queue URL`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-queue-url`)}},[`${r}Arn`]:{Description:`${t} queue ARN`,Value:d.getAtt(r,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t}-queue-arn`)}}}),n.deadLetterQueue)e.addOutputs({[`${r}DLQUrl`]:{Description:`${t} dead letter queue URL`,Value:d.ref(`${r}DLQ`),Export:{Name:d.sub(`\${AWS::StackName}-${t}-dlq-url`)}}})}function xr(e,t){if(t.certificate)to(e,t.certificate);if(t.waf?.enabled)no(e,t.waf);if(t.securityGroups)for(let[n,r]of Object.entries(t.securityGroups))ro(e,n,r)}function to(e,t){if(!t)return;let n=[t.domain];if(t.subdomains)n.push(...t.subdomains);e.addResource("Certificate","AWS::CertificateManager::Certificate",{DomainName:t.domain,SubjectAlternativeNames:t.subdomains,ValidationMethod:t.validationMethod||"DNS",DomainValidationOptions:n.map((r)=>({DomainName:r,HostedZoneId:d.ref("HostedZone")})),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-certificate")}]}),e.addOutputs({CertificateArn:{Description:"ACM Certificate ARN",Value:d.ref("Certificate"),Export:{Name:d.sub("${AWS::StackName}-certificate-arn")}}})}function no(e,t){if(!t)return;let n=[],r=t.rules||["rateLimit","sqlInjection","xss"];if(r.includes("rateLimit"))n.push({Name:"RateLimitRule",Priority:1,Statement:{RateBasedStatement:{Limit:t.rateLimit||2000,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"RateLimitRule"}});let i=n.length+1;if(r.includes("sqlInjection"))n.push({Name:"AWSManagedRulesSQLi",Priority:i++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesSQLiRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesSQLi"}});if(r.includes("xss"))n.push({Name:"AWSManagedRulesXSS",Priority:i++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesXSS"}});if(r.includes("knownBadInputs"))n.push({Name:"AWSManagedRulesKnownBadInputs",Priority:i++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesKnownBadInputs"}});if(r.includes("coreRuleSet"))n.push({Name:"AWSManagedRulesCoreRuleSet",Priority:i++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesCommonRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesCoreRuleSet"}});if(r.includes("linuxRuleSet"))n.push({Name:"AWSManagedRulesLinuxRuleSet",Priority:i++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesLinuxRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesLinuxRuleSet"}});if(r.includes("apiProtection"))n.push({Name:"AWSManagedRulesAPIProtection",Priority:i++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesAmazonIpReputationList"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesAPIProtection"}});if(r.includes("geoBlock"))n.push({Name:"GeoBlockRule",Priority:i++,Statement:{GeoMatchStatement:{CountryCodes:["CN","RU"]}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"GeoBlockRule"}});if(r.includes("connectionLimit"))n.push({Name:"ConnectionLimitRule",Priority:i++,Statement:{RateBasedStatement:{Limit:100,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"ConnectionLimitRule"}});if(e.addResource("WebACL","AWS::WAFv2::WebACL",{Name:d.sub("${AWS::StackName}-waf"),Scope:t.scope||"REGIONAL",DefaultAction:{Allow:{}},Rules:n,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:d.sub("${AWS::StackName}-waf")},Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-waf")}]}),e.hasResource("LoadBalancer"))e.addResource("WebACLAssociation","AWS::WAFv2::WebACLAssociation",{ResourceArn:d.ref("LoadBalancer"),WebACLArn:d.getAtt("WebACL","Arn")},{dependsOn:["WebACL","LoadBalancer"]});e.addOutputs({WebACLId:{Description:"WAF Web ACL ID",Value:d.ref("WebACL"),Export:{Name:d.sub("${AWS::StackName}-waf-id")}},WebACLArn:{Description:"WAF Web ACL ARN",Value:d.getAtt("WebACL","Arn"),Export:{Name:d.sub("${AWS::StackName}-waf-arn")}}})}function ro(e,t,n){if(!n)return;let r=e.toLogicalId(`${t}-security-group`),i=n.ingress?.map((a)=>({IpProtocol:a.protocol,FromPort:a.port,ToPort:a.port,CidrIp:a.cidr,SourceSecurityGroupId:a.source?d.ref(a.source):void 0}))||[],s=n.egress?.map((a)=>({IpProtocol:a.protocol,FromPort:a.port,ToPort:a.port,CidrIp:a.cidr||"0.0.0.0/0"}))||[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}];e.addResource(r,"AWS::EC2::SecurityGroup",{GroupDescription:`Security group for ${t}`,VpcId:d.ref("VPC"),SecurityGroupIngress:i,SecurityGroupEgress:s,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}-sg`)}]},{dependsOn:"VPC"}),e.addOutputs({[`${r}Id`]:{Description:`${t} security group ID`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-sg-id`)}}})}function kr(e,t){for(let[n,r]of Object.entries(t)){if(r.type==="efs"){so(e,n,r);continue}io(e,n,r)}}function io(e,t,n){let r=e.toLogicalId(`${t}-bucket`),i={BucketName:d.sub(`\${AWS::StackName}-${t}`),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]};if(n.versioning)i.VersioningConfiguration={Status:"Enabled"};if(n.encryption)i.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(!n.public)i.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(n.website)i.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"index.html"};if(n.cors&&n.cors.length>0)i.CorsConfiguration={CorsRules:n.cors.map((s)=>({AllowedOrigins:s.allowedOrigins,AllowedMethods:s.allowedMethods,AllowedHeaders:s.allowedHeaders||["*"],MaxAge:s.maxAge||3600}))};if(n.lifecycleRules&&n.lifecycleRules.length>0)i.LifecycleConfiguration={Rules:n.lifecycleRules.map((s)=>({Id:s.id,Status:s.enabled?"Enabled":"Disabled",ExpirationInDays:s.expirationDays,Transitions:s.transitions?.map((a)=>({TransitionInDays:a.days,StorageClass:a.storageClass}))}))};if(n.intelligentTiering)i.IntelligentTieringConfigurations=[{Id:"EntireBucket",Status:"Enabled",Tierings:[{AccessTier:"ARCHIVE_ACCESS",Days:90},{AccessTier:"DEEP_ARCHIVE_ACCESS",Days:180}]}];if(e.addResource(r,"AWS::S3::Bucket",i,{deletionPolicy:n.versioning?"Retain":"Delete"}),n.public)e.addResource(`${r}Policy`,"AWS::S3::BucketPolicy",{Bucket:d.ref(r),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:"s3:GetObject",Resource:d.join("",[Fe.s3Bucket(d.ref(r)),"/*"])}]}},{dependsOn:r});if(e.addOutputs({[`${r}Name`]:{Description:`${t} bucket name`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-bucket`)}},[`${r}Arn`]:{Description:`${t} bucket ARN`,Value:d.getAtt(r,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t}-bucket-arn`)}}}),n.website)e.addOutputs({[`${r}WebsiteURL`]:{Description:`${t} website URL`,Value:d.getAtt(r,"WebsiteURL")}})}function so(e,t,n){let r=e.toLogicalId(`${t}-efs`),i={Encrypted:n.encryption!==!1,PerformanceMode:n.performanceMode||"generalPurpose",ThroughputMode:n.throughputMode||"bursting",FileSystemTags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]};if(n.lifecyclePolicy){if(i.LifecyclePolicies=[],n.lifecyclePolicy.transitionToIA)i.LifecyclePolicies.push({TransitionToIA:`AFTER_${n.lifecyclePolicy.transitionToIA}_DAYS`});if(n.lifecyclePolicy.transitionToPrimaryStorageClass)i.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"})}e.addResource(r,"AWS::EFS::FileSystem",i,{deletionPolicy:"Retain"});let s=2;for(let a=0;a<s;a++)e.addResource(`${r}MountTarget${a+1}`,"AWS::EFS::MountTarget",{FileSystemId:d.ref(r),SubnetId:d.ref(`PrivateSubnet${a+1}`),SecurityGroups:[d.ref("EFSSecurityGroup")]},{dependsOn:[r,`PrivateSubnet${a+1}`]});e.addResource("EFSSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for EFS mount targets",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-efs-sg")}]},{dependsOn:"VPC"}),e.addOutputs({[`${r}Id`]:{Description:`${t} EFS file system ID`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-efs`)}}})}class Mr{template;config;resourceDependencies;constructor(e){this.config=e,this.resourceDependencies=new Map,this.template={AWSTemplateFormatVersion:"2010-09-09",Description:`Infrastructure for ${e.project.name} (${e.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:d.equals(d.ref("Environment"),"production"),HasDomain:d.not([d.equals(this.config.environments?.production?.domain||"","")])}}addResources(){let{infrastructure:e}=this.config;if(!e)return;if(e.network)this.addNetworkResources(e.network);if(e.storage)this.addStorageResources(e.storage);if(e.compute)this.addComputeResources(e.compute);if(e.databases)this.addDatabaseResources(e.databases);if(e.cache)this.addCacheResources(e.cache);if(e.cdn)this.addCDNResources(e.cdn);if(e.apiGateway)this.addApiGatewayResources(e.apiGateway);if(e.functions)this.addFunctionResources(e.functions);if(e.queues)this.addQueueResources(e.queues);if(e.messaging)this.addMessagingResources(e.messaging);if(e.monitoring)this.addMonitoringResources(e.monitoring);if(e.security)this.addSecurityResources(e.security)}initializeOutputs(){let e=this.template.Outputs||{};if(this.template.Outputs={StackName:{Description:"Stack name",Value:d.ref("AWS::StackName"),Export:{Name:d.sub("${AWS::StackName}-Name")}},Region:{Description:"AWS Region",Value:d.ref("AWS::Region"),Export:{Name:d.sub("${AWS::StackName}-Region")}},...e},this.config.environments?.production?.domain)this.template.Outputs.Domain={Description:"Production domain",Value:this.config.environments.production.domain,Condition:"HasDomain"}}addResource(e,t,n,r){let i={Type:t,Properties:n};if(r?.dependsOn)i.DependsOn=r.dependsOn,this.trackDependency(e,r.dependsOn);if(r?.condition)i.Condition=r.condition;if(r?.deletionPolicy)i.DeletionPolicy=r.deletionPolicy;if(r?.updateReplacePolicy)i.UpdateReplacePolicy=r.updateReplacePolicy;this.template.Resources[e]=i}addOutputs(e){this.template.Outputs={...this.template.Outputs,...e}}getOutputs(){return this.template.Outputs||{}}hasResource(e){return e in this.template.Resources}getResource(e){return this.template.Resources[e]}trackDependency(e,t){if(!this.resourceDependencies.has(e))this.resourceDependencies.set(e,new Set);(Array.isArray(t)?t:[t]).forEach((r)=>this.resourceDependencies.get(e).add(r))}resolveDependencies(){let e=new Set,t=new Set,n=(r)=>{if(t.has(r))throw Error(`Circular dependency detected involving resource: ${r}`);if(e.has(r))return!0;e.add(r),t.add(r);let i=this.resourceDependencies.get(r);if(i)for(let s of i)n(s);return t.delete(r),!0};for(let r of this.resourceDependencies.keys())n(r)}toLogicalId(e){return e.split(/[-_\s]/).map((t)=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}addNetworkResources(e){Dr(this,e)}addStorageResources(e){kr(this,e)}addComputeResources(e){Tr(this,e)}addDatabaseResources(e){Pr(this,e)}addFunctionResources(e){Er(this,e)}addCacheResources(e){Ar(this,e)}addQueueResources(e){Nr(this,e)}addMessagingResources(e){wr(this,e)}addCDNResources(e){Cr(this,e)}addApiGatewayResources(e){Sr(this,e)}addMonitoringResources(e){Ir(this,e)}addSecurityResources(e){xr(this,e)}}function tg(e){return new Mr(e).build()}function rg(e){let{name:t,slug:n,domain:r,subdomain:i}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i&&r?`${i}.${r}`:r}},infrastructure:{storage:{assets:{public:!0,versioning:!1,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"],allowedHeaders:["*"],maxAge:3600}]}},cdn:{enabled:!0,customDomain:r?{domain:i&&r?`${i}.${r}`:r,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 sg(e){let{name:t,slug:n,domain:r,instanceType:i="t3.small",minInstances:s=2,maxInstances:a=10}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:i,ami:"ubuntu-22.04",keyPair:`${n}-key`,autoScaling:{min:s,max:a,desired:s,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:r?{domain:r,subdomains:[`*.${r}`],validationMethod:"DNS"}:void 0}}}}function og(e){let{name:t,slug:n,domain:r,taskCpu:i="256",taskMemory:s="512",desiredCount:a=2}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:0}},compute:{fargate:{taskDefinition:{cpu:i,memory:s,containerDefinitions:[{name:"app",image:`${n}-app:latest`,portMappings:[{containerPort:3000}],environment:[],secrets:[]}]},service:{desiredCount:a,healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},autoScaling:{min:a,max:a*5,targetCPU:70,targetMemory:80}},loadBalancer:{type:"application"}}},databases:{dynamodb:{tables:{[`${n}-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:`${n}-queue`}]}},security:{certificate:r?{domain:r,subdomains:[`*.${r}`],validationMethod:"DNS"}:void 0}}}}function lg(e){let{name:t,slug:n,entry:r,domain:i,runtime:s="nodejs20.x",memory:a=1024,build:o,deploy:c,assets:l,queues:u=!0,scheduler:m="on",region:p="us-east-1"}=e;return{project:{name:t,slug:n,region:p},mode:"serverless",environments:{production:{type:"production",domain:i,app:{kind:"node",runtime:s,entry:r,memory:a,build:o,deploy:c,assets:l,queues:u,scheduler:m,domain:i}}}}}function mg(e){let t=e.database!==!1,n=e.cache!==!1,r=e.queue!==!1;return{project:{name:e.name,slug:e.slug,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:e.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:e.imageUri,portMappings:[{containerPort:3000}],environment:[{name:"NODE_ENV",value:"production"},{name:"PORT",value:"3000"},{name:"AWS_REGION",value:d.ref("AWS::Region")},...t?[{name:"DB_HOST",value:d.getAtt("PostgresDb","Endpoint.Address")},{name:"DB_PORT",value:d.getAtt("PostgresDb","Endpoint.Port")}]:[],...n?[{name:"REDIS_HOST",value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address")},{name:"REDIS_PORT",value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port")},{name:"REDIS_TLS",value:"true"}]:[],...r?[{name:"QUEUE_URL",value:d.ref("JobsQueue")}]:[],{name:"MAIL_TRANSPORT",value:"ses"}],secrets:t?[{name:"DB_USERNAME",valueFrom:d.sub("${DBSecret}:username::")},{name:"DB_PASSWORD",valueFrom:d.sub("${DBSecret}:password::")}]:[]}]},service:{desiredCount:e.desiredCount||1,healthCheck:{path:"/api/health",interval:30,timeout:5},autoScaling:{min:e.desiredCount||1,max:6,targetCPU:70}},loadBalancer:{type:"application",...e.certificateArn?{customDomain:{domain:e.domain,certificateArn:e.certificateArn}}:{},...e.originVerifySecret?{originVerifyHeader:{name:"X-Origin-Verify",value:e.originVerifySecret}}:{}}}},...t?{databases:{postgres:{engine:"postgres",version:"16",instanceClass:"db.t4g.micro",allocatedStorage:20,maxAllocatedStorage:100,multiAZ:!1,backupRetentionDays:7,deletionProtection:!0}}}:{},...n?{cache:{redis:{nodeType:"cache.t4g.micro",numCacheNodes:2,engine:"redis",engineVersion:"7.1",automaticFailoverEnabled:!0,snapshotRetentionLimit:5}}}:{},...r?{queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0,maxReceiveCount:3,receiveMessageWaitTime:20}}}:{}}}}function pg(e){let{name:t,slug:n,domain:r,apiSubdomain:i="api"}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},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:r,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:`${n}-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:`${i}.${r}`,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:r,subdomains:[`*.${r}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss"]}}}}}function yg(e){let{name:t,slug:n,domain:r}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{apiGateway:{type:"HTTP",cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"],allowHeaders:["Content-Type","Authorization"],maxAge:3600},customDomain:r?{domain:r,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:{[`${n}-users`]:{partitionKey:{name:"userId",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"EmailIndex",partitionKey:{name:"email",type:"S"},projection:"ALL"}]},[`${n}-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:r?{domain:r,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 hg(e){let{name:t,slug:n,domain:r,instanceType:i="t3.small"}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:i,ami:"ubuntu-22.04",keyPair:`${n}-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:r,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,origins:[{type:"alb",pathPattern:"/wp-content/*"}]},security:{certificate:{domain:r,subdomains:[`www.${r}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","wordpressRules"]}}}}}function Sg(e){let{name:t,slug:n,domain:r,apiDomain:i}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},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:r,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},...i?{api:{runtime:"nodejs20.x",handler:"dist/api/index.handler",memory:1024,timeout:30,events:[{type:"http",path:"/{proxy+}",method:"ANY"}]}}:{}},apiGateway:i?{type:"HTTP",customDomain:{domain:i,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:[r],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:r,subdomains:i?[i]:[],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","geoBlock"]}}}}}function Cg(e){let{name:t,slug:n,domain:r,services:i}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:3,natGateways:2}},compute:{services:i.map((s)=>({name:s.name,type:"fargate",taskDefinition:{cpu:s.cpu||"256",memory:s.memory||"512",containerDefinitions:[{name:s.name,image:`${n}-${s.name}:latest`,portMappings:[{containerPort:s.port}],healthCheck:{command:["CMD-SHELL",`curl -f http://localhost:${s.port}/health || exit 1`],interval:30,timeout:5,retries:3}}]},service:{desiredCount:s.desiredCount||2,serviceDiscovery:{enabled:!0,namespace:`${n}.local`},autoScaling:{min:2,max:10,targetCPU:70}}}))},apiGateway:{type:"HTTP",customDomain:{domain:r,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"]},routes:i.map((s)=>({path:`/${s.name}/{proxy+}`,integration:{type:"vpc-link",service:s.name}}))},databases:{dynamodb:{tables:Object.fromEntries(i.map((s)=>[`${n}-${s.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:`${n}-events`,subscriptions:i.map((s)=>({protocol:"sqs",endpoint:`${n}-${s.name}-queue`,filterPolicy:{service:[s.name]}}))}}},monitoring:{dashboard:{name:`${n}-microservices`,widgets:i.map((s)=>({type:"metric",metrics:[{service:s.name,metric:"CPUUtilization"},{service:s.name,metric:"MemoryUtilization"},{service:s.name,metric:"RequestCount"}]}))},alarms:i.flatMap((s)=>[{name:`${s.name}-high-cpu`,metric:"CPUUtilization",threshold:80,service:s.name},{name:`${s.name}-errors`,metric:"Errors",threshold:10,service:s.name}])},security:{certificate:{domain:r,validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}}}}}function Tg(e){let{name:t,slug:n,domain:r}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{apiGateway:{type:"websocket",customDomain:r?{domain:r,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:`${n}-messages`,startingPosition:"LATEST",batchSize:100}]}},databases:{dynamodb:{tables:{[`${n}-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"}]},[`${n}-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"}]},[`${n}-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:`${n}-realtime`,widgets:[{type:"metric",metrics:["WebSocketConnections","MessagesSent","IntegrationLatency"]}]}},security:{certificate:r?{domain:r,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","connectionLimit"]}}}}}function Pg(e){let{name:t,slug:n,retentionDays:r=7}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",infrastructure:{streaming:{dataStream:{name:`${n}-stream`,shardCount:2,retentionPeriod:r*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:`${n}-stream`,batchSize:1000,startingPosition:"LATEST",parallelizationFactor:10}]},transformer:{runtime:"nodejs20.x",handler:"dist/processors/transform.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${n}-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:`${n}_analytics`,workgroup:`${n}-workgroup`,outputBucket:`${n}-query-results`,tables:[{name:"raw_events",location:`s3://${n}-raw/events/`,format:"parquet",partitionKeys:["year","month","day"]},{name:"processed_events",location:`s3://${n}-processed/events/`,format:"parquet",partitionKeys:["year","month","day"]}]},glue:{crawlers:[{name:`${n}-crawler`,databaseName:`${n}_analytics`,s3Targets:[`s3://${n}-raw/`,`s3://${n}-processed/`],schedule:"cron(0 2 * * ? *)"}],jobs:[{name:`${n}-etl-job`,scriptLocation:`s3://${n}-scripts/etl.py`,role:`${n}-glue-role`,maxCapacity:10,timeout:120}]}},databases:{dynamodb:{tables:{[`${n}-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:`${n}-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:`${n}-pipeline`,widgets:[{type:"metric",metrics:["KinesisIncomingRecords","LambdaInvocations","S3ObjectsCreated","GlueJobsSucceeded"]}]},alarms:[{metric:"LambdaErrors",threshold:10,evaluationPeriods:1},{metric:"KinesisIteratorAge",threshold:60000,evaluationPeriods:2}]}}}}function wg(e){let{name:t,slug:n,domain:r,modelS3Path:i=`s3://${n}-models/`,instanceType:s="ml.t3.medium"}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},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:`${n}-inference`,modelS3Path:i,instanceType:s,initialInstanceCount:1,autoScaling:{minInstances:1,maxInstances:5,targetInvocationsPerInstance:1000}}],trainingJobs:[{name:`${n}-training`,algorithmSpecification:{trainingImage:"TO_BE_SPECIFIED",trainingInputMode:"File"},instanceType:"ml.p3.2xlarge",instanceCount:1,volumeSizeInGB:50,maxRuntimeInSeconds:86400}]}},apiGateway:{type:"HTTP",customDomain:r?{domain:r,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:`${n}-inference`,MODEL_BUCKET:`${n}-models`}},"batch-predict":{runtime:"python3.11",handler:"handlers/batchPredict.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${n}-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:{[`${n}-predictions`]:{partitionKey:{name:"requestId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0},[`${n}-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:`${n}-ml`,widgets:[{type:"metric",metrics:["SageMakerInvocations","SageMakerModelLatency","APIGatewayRequests","LambdaErrors"]}]},alarms:[{metric:"SageMakerModelLatency",threshold:1000,evaluationPeriods:2},{metric:"SageMakerInvocationErrors",threshold:10,evaluationPeriods:1}]},security:{certificate:r?{domain:r,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","apiProtection"]}}}}}function Dg(e){let{name:t,slug:n,domain:r,instanceType:i="t3.medium",minInstances:s=2,maxInstances:a=10,databaseEngine:o="mysql",sessionStore:c="redis"}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:2}},compute:{server:{instanceType:i,ami:"ubuntu-22.04",autoScaling:{min:s,max:a,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
2466
+ | limit 20`,region:d.ref("AWS::Region"),title:`Logs: ${s.logGroup}`}});else if(s.type==="text"&&s.text)n.push({type:"text",x:r,y:i,width:a,height:o,properties:{markdown:s.text}});if(r+=a,r>=24)r=0,i+=o}),e.addResource("CloudWatchDashboard","AWS::CloudWatch::Dashboard",{DashboardName:d.sub(`\${AWS::StackName}-${t.name}`),DashboardBody:JSON.stringify({widgets:n})}),e.addOutputs({DashboardURL:{Description:"CloudWatch Dashboard URL",Value:d.sub("https://console.aws.amazon.com/cloudwatch/home?region=${AWS::Region}#dashboards:name=${CloudWatchDashboard}")}})}function Za(e,t,n){let r=e.toLogicalId(`${t}-log-group`);e.addResource(r,"AWS::Logs::LogGroup",{LogGroupName:d.sub(`/aws/\${AWS::StackName}/${t}`),RetentionInDays:n||14,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]})}function Yt(e,t){if(t)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"}[t.toLowerCase()]||"AWS/CloudWatch";let n=e.toLowerCase();if(n.includes("cpu")||n.includes("memory")||n.includes("network"))return"AWS/EC2";if(n.includes("lambda")||n.includes("invocation")||n.includes("duration"))return"AWS/Lambda";if(n.includes("request")||n.includes("latency")||n.includes("target"))return"AWS/ApplicationELB";if(n.includes("database")||n.includes("connection"))return"AWS/RDS";if(n.includes("read")||n.includes("write")||n.includes("consumed"))return"AWS/DynamoDB";return"AWS/CloudWatch"}function Xa(e){return{ec2:[{Name:"InstanceId",Value:d.ref("EC2Instance")}],ecs:[{Name:"ClusterName",Value:d.ref("ECSCluster")},{Name:"ServiceName",Value:d.getAtt("ECSService","Name")}],lambda:[{Name:"FunctionName",Value:d.ref("LambdaFunction")}],rds:[{Name:"DBInstanceIdentifier",Value:d.ref("Database")}],dynamodb:[{Name:"TableName",Value:d.ref("DynamoDBTable")}],alb:[{Name:"LoadBalancer",Value:d.getAtt("LoadBalancer","LoadBalancerFullName")}],apigateway:[{Name:"ApiName",Value:d.ref("HttpApi")}]}[e.toLowerCase()]||[]}function Dr(e,t){if(!t.vpc)return;let{cidr:n="10.0.0.0/16",availabilityZones:r=2,natGateways:i=1,enableDnsHostnames:s=!0,enableDnsSupport:a=!0}=t.vpc;e.addResource("VPC","AWS::EC2::VPC",{CidrBlock:n,EnableDnsHostnames:s,EnableDnsSupport:a,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-vpc")}]}),e.addResource("InternetGateway","AWS::EC2::InternetGateway",{Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-igw")}]}),e.addResource("VPCGatewayAttachment","AWS::EC2::VPCGatewayAttachment",{VpcId:d.ref("VPC"),InternetGatewayId:d.ref("InternetGateway")},{dependsOn:["VPC","InternetGateway"]});let o=[];for(let m=0;m<r;m++){let p=`PublicSubnet${m+1}`;o.push(p),e.addResource(p,"AWS::EC2::Subnet",{VpcId:d.ref("VPC"),CidrBlock:d.select(m,d.cidr(d.getAtt("VPC","CidrBlock"),r*2,8)),AvailabilityZone:d.select(m,d.getAZs()),MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-public-${m+1}`)},{Key:"Type",Value:"public"}]},{dependsOn:"VPC"})}let c=[];for(let m=0;m<r;m++){let p=`PrivateSubnet${m+1}`;c.push(p),e.addResource(p,"AWS::EC2::Subnet",{VpcId:d.ref("VPC"),CidrBlock:d.select(m+r,d.cidr(d.getAtt("VPC","CidrBlock"),r*2,8)),AvailabilityZone:d.select(m,d.getAZs()),MapPublicIpOnLaunch:!1,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-private-${m+1}`)},{Key:"Type",Value:"private"}]},{dependsOn:"VPC"})}let l=[];for(let m=0;m<i;m++){let p=`NatEIP${m+1}`;l.push(p),e.addResource(p,"AWS::EC2::EIP",{Domain:"vpc",Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-nat-eip-${m+1}`)}]},{dependsOn:"VPCGatewayAttachment"})}let u=[];for(let m=0;m<i;m++){let p=`NatGateway${m+1}`;u.push(p);let g=m%r;e.addResource(p,"AWS::EC2::NatGateway",{AllocationId:d.getAtt(l[m],"AllocationId"),SubnetId:d.ref(o[g]),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-nat-${m+1}`)}]},{dependsOn:[l[m],o[g]]})}e.addResource("PublicRouteTable","AWS::EC2::RouteTable",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-public-rt")}]},{dependsOn:"VPC"}),e.addResource("PublicRoute","AWS::EC2::Route",{RouteTableId:d.ref("PublicRouteTable"),DestinationCidrBlock:"0.0.0.0/0",GatewayId:d.ref("InternetGateway")},{dependsOn:["PublicRouteTable","VPCGatewayAttachment"]}),o.forEach((m,p)=>{e.addResource(`PublicSubnetRouteTableAssociation${p+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:d.ref(m),RouteTableId:d.ref("PublicRouteTable")},{dependsOn:[m,"PublicRouteTable"]})}),c.forEach((m,p)=>{let g=`PrivateRouteTable${p+1}`,y=p%i;e.addResource(g,"AWS::EC2::RouteTable",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-private-rt-${p+1}`)}]},{dependsOn:"VPC"}),e.addResource(`PrivateRoute${p+1}`,"AWS::EC2::Route",{RouteTableId:d.ref(g),DestinationCidrBlock:"0.0.0.0/0",NatGatewayId:d.ref(u[y])},{dependsOn:[g,u[y]]}),e.addResource(`PrivateSubnetRouteTableAssociation${p+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:d.ref(m),RouteTableId:d.ref(g)},{dependsOn:[m,g]})}),e.addResource("S3VPCEndpoint","AWS::EC2::VPCEndpoint",{VpcId:d.ref("VPC"),ServiceName:d.sub("com.amazonaws.${AWS::Region}.s3"),VpcEndpointType:"Gateway",RouteTableIds:[d.ref("PublicRouteTable"),...Array.from({length:r},(m,p)=>d.ref(`PrivateRouteTable${p+1}`))]},{dependsOn:"VPC"}),e.addResource("NetworkAcl","AWS::EC2::NetworkAcl",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-nacl")}]},{dependsOn:"VPC"}),e.addResource("NetworkAclEntryInbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:d.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),e.addResource("NetworkAclEntryOutbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:d.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,Egress:!0,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),e.addOutputs({VPCId:{Description:"VPC ID",Value:d.ref("VPC"),Export:{Name:d.sub("${AWS::StackName}-VPC")}},PublicSubnets:{Description:"Public subnet IDs",Value:d.join(",",o.map((m)=>d.ref(m))),Export:{Name:d.sub("${AWS::StackName}-PublicSubnets")}},PrivateSubnets:{Description:"Private subnet IDs",Value:d.join(",",c.map((m)=>d.ref(m))),Export:{Name:d.sub("${AWS::StackName}-PrivateSubnets")}}})}function Nr(e,t){for(let[n,r]of Object.entries(t))eo(e,n,r)}function eo(e,t,n){let r=e.toLogicalId(`${t}-queue`),i=n.fifo||!1,s;if(n.deadLetterQueue){let o=`${r}DLQ`;e.addResource(o,"AWS::SQS::Queue",{QueueName:i?d.sub(`\${AWS::StackName}-${t}-dlq.fifo`):d.sub(`\${AWS::StackName}-${t}-dlq`),FifoQueue:i,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}-dlq`)}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),s=d.getAtt(o,"Arn")}let a={QueueName:i?d.sub(`\${AWS::StackName}-${t}.fifo`):d.sub(`\${AWS::StackName}-${t}`),FifoQueue:i,VisibilityTimeout:n.visibilityTimeout||30,MessageRetentionPeriod:n.messageRetentionPeriod||345600,ReceiveMessageWaitTimeSeconds:n.receiveMessageWaitTime||0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]};if(i&&n.contentBasedDeduplication)a.ContentBasedDeduplication=!0;if(n.deadLetterQueue&&s)a.RedrivePolicy={deadLetterTargetArn:s,maxReceiveCount:n.maxReceiveCount||3};if(e.addResource(r,"AWS::SQS::Queue",a,{dependsOn:n.deadLetterQueue?`${r}DLQ`:void 0,deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),e.addResource(`${r}Policy`,"AWS::SQS::QueuePolicy",{Queues:[d.ref(r)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","events.amazonaws.com","sns.amazonaws.com"]},Action:"sqs:SendMessage",Resource:d.getAtt(r,"Arn"),Condition:{ArnEquals:{"aws:SourceArn":d.sub("arn:aws:*:${AWS::Region}:${AWS::AccountId}:*")}}}]}},{dependsOn:r}),e.addOutputs({[`${r}Url`]:{Description:`${t} queue URL`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-queue-url`)}},[`${r}Arn`]:{Description:`${t} queue ARN`,Value:d.getAtt(r,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t}-queue-arn`)}}}),n.deadLetterQueue)e.addOutputs({[`${r}DLQUrl`]:{Description:`${t} dead letter queue URL`,Value:d.ref(`${r}DLQ`),Export:{Name:d.sub(`\${AWS::StackName}-${t}-dlq-url`)}}})}function xr(e,t){if(t.certificate)to(e,t.certificate);if(t.waf?.enabled)no(e,t.waf);if(t.securityGroups)for(let[n,r]of Object.entries(t.securityGroups))ro(e,n,r)}function to(e,t){if(!t)return;let n=[t.domain];if(t.subdomains)n.push(...t.subdomains);e.addResource("Certificate","AWS::CertificateManager::Certificate",{DomainName:t.domain,SubjectAlternativeNames:t.subdomains,ValidationMethod:t.validationMethod||"DNS",DomainValidationOptions:n.map((r)=>({DomainName:r,HostedZoneId:d.ref("HostedZone")})),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-certificate")}]}),e.addOutputs({CertificateArn:{Description:"ACM Certificate ARN",Value:d.ref("Certificate"),Export:{Name:d.sub("${AWS::StackName}-certificate-arn")}}})}function no(e,t){if(!t)return;let n=[],r=t.rules||["rateLimit","sqlInjection","xss"];if(r.includes("rateLimit"))n.push({Name:"RateLimitRule",Priority:1,Statement:{RateBasedStatement:{Limit:t.rateLimit||2000,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"RateLimitRule"}});let i=n.length+1;if(r.includes("sqlInjection"))n.push({Name:"AWSManagedRulesSQLi",Priority:i++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesSQLiRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesSQLi"}});if(r.includes("xss"))n.push({Name:"AWSManagedRulesXSS",Priority:i++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesXSS"}});if(r.includes("knownBadInputs"))n.push({Name:"AWSManagedRulesKnownBadInputs",Priority:i++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesKnownBadInputs"}});if(r.includes("coreRuleSet"))n.push({Name:"AWSManagedRulesCoreRuleSet",Priority:i++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesCommonRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesCoreRuleSet"}});if(r.includes("linuxRuleSet"))n.push({Name:"AWSManagedRulesLinuxRuleSet",Priority:i++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesLinuxRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesLinuxRuleSet"}});if(r.includes("apiProtection"))n.push({Name:"AWSManagedRulesAPIProtection",Priority:i++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesAmazonIpReputationList"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesAPIProtection"}});if(r.includes("geoBlock"))n.push({Name:"GeoBlockRule",Priority:i++,Statement:{GeoMatchStatement:{CountryCodes:["CN","RU"]}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"GeoBlockRule"}});if(r.includes("connectionLimit"))n.push({Name:"ConnectionLimitRule",Priority:i++,Statement:{RateBasedStatement:{Limit:100,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"ConnectionLimitRule"}});if(e.addResource("WebACL","AWS::WAFv2::WebACL",{Name:d.sub("${AWS::StackName}-waf"),Scope:t.scope||"REGIONAL",DefaultAction:{Allow:{}},Rules:n,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:d.sub("${AWS::StackName}-waf")},Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-waf")}]}),e.hasResource("LoadBalancer"))e.addResource("WebACLAssociation","AWS::WAFv2::WebACLAssociation",{ResourceArn:d.ref("LoadBalancer"),WebACLArn:d.getAtt("WebACL","Arn")},{dependsOn:["WebACL","LoadBalancer"]});e.addOutputs({WebACLId:{Description:"WAF Web ACL ID",Value:d.ref("WebACL"),Export:{Name:d.sub("${AWS::StackName}-waf-id")}},WebACLArn:{Description:"WAF Web ACL ARN",Value:d.getAtt("WebACL","Arn"),Export:{Name:d.sub("${AWS::StackName}-waf-arn")}}})}function ro(e,t,n){if(!n)return;let r=e.toLogicalId(`${t}-security-group`),i=n.ingress?.map((a)=>({IpProtocol:a.protocol,FromPort:a.port,ToPort:a.port,CidrIp:a.cidr,SourceSecurityGroupId:a.source?d.ref(a.source):void 0}))||[],s=n.egress?.map((a)=>({IpProtocol:a.protocol,FromPort:a.port,ToPort:a.port,CidrIp:a.cidr||"0.0.0.0/0"}))||[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}];e.addResource(r,"AWS::EC2::SecurityGroup",{GroupDescription:`Security group for ${t}`,VpcId:d.ref("VPC"),SecurityGroupIngress:i,SecurityGroupEgress:s,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}-sg`)}]},{dependsOn:"VPC"}),e.addOutputs({[`${r}Id`]:{Description:`${t} security group ID`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-sg-id`)}}})}function kr(e,t){for(let[n,r]of Object.entries(t)){if(r.type==="efs"){so(e,n,r);continue}io(e,n,r)}}function io(e,t,n){let r=e.toLogicalId(`${t}-bucket`),i={BucketName:d.sub(`\${AWS::StackName}-${t}`),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]};if(n.versioning)i.VersioningConfiguration={Status:"Enabled"};if(n.encryption)i.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(!n.public)i.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(n.website)i.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"index.html"};if(n.cors&&n.cors.length>0)i.CorsConfiguration={CorsRules:n.cors.map((s)=>({AllowedOrigins:s.allowedOrigins,AllowedMethods:s.allowedMethods,AllowedHeaders:s.allowedHeaders||["*"],MaxAge:s.maxAge||3600}))};if(n.lifecycleRules&&n.lifecycleRules.length>0)i.LifecycleConfiguration={Rules:n.lifecycleRules.map((s)=>({Id:s.id,Status:s.enabled?"Enabled":"Disabled",ExpirationInDays:s.expirationDays,Transitions:s.transitions?.map((a)=>({TransitionInDays:a.days,StorageClass:a.storageClass}))}))};if(n.intelligentTiering)i.IntelligentTieringConfigurations=[{Id:"EntireBucket",Status:"Enabled",Tierings:[{AccessTier:"ARCHIVE_ACCESS",Days:90},{AccessTier:"DEEP_ARCHIVE_ACCESS",Days:180}]}];if(e.addResource(r,"AWS::S3::Bucket",i,{deletionPolicy:n.versioning?"Retain":"Delete"}),n.public)e.addResource(`${r}Policy`,"AWS::S3::BucketPolicy",{Bucket:d.ref(r),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:"s3:GetObject",Resource:d.join("",[_e.s3Bucket(d.ref(r)),"/*"])}]}},{dependsOn:r});if(e.addOutputs({[`${r}Name`]:{Description:`${t} bucket name`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-bucket`)}},[`${r}Arn`]:{Description:`${t} bucket ARN`,Value:d.getAtt(r,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t}-bucket-arn`)}}}),n.website)e.addOutputs({[`${r}WebsiteURL`]:{Description:`${t} website URL`,Value:d.getAtt(r,"WebsiteURL")}})}function so(e,t,n){let r=e.toLogicalId(`${t}-efs`),i={Encrypted:n.encryption!==!1,PerformanceMode:n.performanceMode||"generalPurpose",ThroughputMode:n.throughputMode||"bursting",FileSystemTags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]};if(n.lifecyclePolicy){if(i.LifecyclePolicies=[],n.lifecyclePolicy.transitionToIA)i.LifecyclePolicies.push({TransitionToIA:`AFTER_${n.lifecyclePolicy.transitionToIA}_DAYS`});if(n.lifecyclePolicy.transitionToPrimaryStorageClass)i.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"})}e.addResource(r,"AWS::EFS::FileSystem",i,{deletionPolicy:"Retain"});let s=2;for(let a=0;a<s;a++)e.addResource(`${r}MountTarget${a+1}`,"AWS::EFS::MountTarget",{FileSystemId:d.ref(r),SubnetId:d.ref(`PrivateSubnet${a+1}`),SecurityGroups:[d.ref("EFSSecurityGroup")]},{dependsOn:[r,`PrivateSubnet${a+1}`]});e.addResource("EFSSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for EFS mount targets",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-efs-sg")}]},{dependsOn:"VPC"}),e.addOutputs({[`${r}Id`]:{Description:`${t} EFS file system ID`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-efs`)}}})}class Mr{template;config;resourceDependencies;constructor(e){this.config=e,this.resourceDependencies=new Map,this.template={AWSTemplateFormatVersion:"2010-09-09",Description:`Infrastructure for ${e.project.name} (${e.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:d.equals(d.ref("Environment"),"production"),HasDomain:d.not([d.equals(this.config.environments?.production?.domain||"","")])}}addResources(){let{infrastructure:e}=this.config;if(!e)return;if(e.network)this.addNetworkResources(e.network);if(e.storage)this.addStorageResources(e.storage);if(e.compute)this.addComputeResources(e.compute);if(e.databases)this.addDatabaseResources(e.databases);if(e.cache)this.addCacheResources(e.cache);if(e.cdn)this.addCDNResources(e.cdn);if(e.apiGateway)this.addApiGatewayResources(e.apiGateway);if(e.functions)this.addFunctionResources(e.functions);if(e.queues)this.addQueueResources(e.queues);if(e.messaging)this.addMessagingResources(e.messaging);if(e.monitoring)this.addMonitoringResources(e.monitoring);if(e.security)this.addSecurityResources(e.security)}initializeOutputs(){let e=this.template.Outputs||{};if(this.template.Outputs={StackName:{Description:"Stack name",Value:d.ref("AWS::StackName"),Export:{Name:d.sub("${AWS::StackName}-Name")}},Region:{Description:"AWS Region",Value:d.ref("AWS::Region"),Export:{Name:d.sub("${AWS::StackName}-Region")}},...e},this.config.environments?.production?.domain)this.template.Outputs.Domain={Description:"Production domain",Value:this.config.environments.production.domain,Condition:"HasDomain"}}addResource(e,t,n,r){let i={Type:t,Properties:n};if(r?.dependsOn)i.DependsOn=r.dependsOn,this.trackDependency(e,r.dependsOn);if(r?.condition)i.Condition=r.condition;if(r?.deletionPolicy)i.DeletionPolicy=r.deletionPolicy;if(r?.updateReplacePolicy)i.UpdateReplacePolicy=r.updateReplacePolicy;this.template.Resources[e]=i}addOutputs(e){this.template.Outputs={...this.template.Outputs,...e}}getOutputs(){return this.template.Outputs||{}}hasResource(e){return e in this.template.Resources}getResource(e){return this.template.Resources[e]}trackDependency(e,t){if(!this.resourceDependencies.has(e))this.resourceDependencies.set(e,new Set);(Array.isArray(t)?t:[t]).forEach((r)=>this.resourceDependencies.get(e).add(r))}resolveDependencies(){let e=new Set,t=new Set,n=(r)=>{if(t.has(r))throw Error(`Circular dependency detected involving resource: ${r}`);if(e.has(r))return!0;e.add(r),t.add(r);let i=this.resourceDependencies.get(r);if(i)for(let s of i)n(s);return t.delete(r),!0};for(let r of this.resourceDependencies.keys())n(r)}toLogicalId(e){return e.split(/[-_\s]/).map((t)=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}addNetworkResources(e){Dr(this,e)}addStorageResources(e){kr(this,e)}addComputeResources(e){Tr(this,e)}addDatabaseResources(e){Pr(this,e)}addFunctionResources(e){Er(this,e)}addCacheResources(e){Ar(this,e)}addQueueResources(e){Nr(this,e)}addMessagingResources(e){wr(this,e)}addCDNResources(e){Cr(this,e)}addApiGatewayResources(e){Sr(this,e)}addMonitoringResources(e){Ir(this,e)}addSecurityResources(e){xr(this,e)}}function tg(e){return new Mr(e).build()}function rg(e){let{name:t,slug:n,domain:r,subdomain:i}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i&&r?`${i}.${r}`:r}},infrastructure:{storage:{assets:{public:!0,versioning:!1,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"],allowedHeaders:["*"],maxAge:3600}]}},cdn:{enabled:!0,customDomain:r?{domain:i&&r?`${i}.${r}`:r,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 sg(e){let{name:t,slug:n,domain:r,instanceType:i="t3.small",minInstances:s=2,maxInstances:a=10}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:i,ami:"ubuntu-22.04",keyPair:`${n}-key`,autoScaling:{min:s,max:a,desired:s,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:r?{domain:r,subdomains:[`*.${r}`],validationMethod:"DNS"}:void 0}}}}function og(e){let{name:t,slug:n,domain:r,taskCpu:i="256",taskMemory:s="512",desiredCount:a=2}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:0}},compute:{fargate:{taskDefinition:{cpu:i,memory:s,containerDefinitions:[{name:"app",image:`${n}-app:latest`,portMappings:[{containerPort:3000}],environment:[],secrets:[]}]},service:{desiredCount:a,healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},autoScaling:{min:a,max:a*5,targetCPU:70,targetMemory:80}},loadBalancer:{type:"application"}}},databases:{dynamodb:{tables:{[`${n}-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:`${n}-queue`}]}},security:{certificate:r?{domain:r,subdomains:[`*.${r}`],validationMethod:"DNS"}:void 0}}}}function lg(e){let{name:t,slug:n,entry:r,domain:i,runtime:s="nodejs20.x",memory:a=1024,build:o,deploy:c,assets:l,queues:u=!0,scheduler:m="on",region:p="us-east-1"}=e;return{project:{name:t,slug:n,region:p},mode:"serverless",environments:{production:{type:"production",domain:i,app:{kind:"node",runtime:s,entry:r,memory:a,build:o,deploy:c,assets:l,queues:u,scheduler:m,domain:i}}}}}function mg(e){let t=e.database!==!1,n=e.cache!==!1,r=e.queue!==!1;return{project:{name:e.name,slug:e.slug,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:e.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:e.imageUri,portMappings:[{containerPort:3000}],environment:[{name:"NODE_ENV",value:"production"},{name:"PORT",value:"3000"},{name:"AWS_REGION",value:d.ref("AWS::Region")},...t?[{name:"DB_HOST",value:d.getAtt("PostgresDb","Endpoint.Address")},{name:"DB_PORT",value:d.getAtt("PostgresDb","Endpoint.Port")}]:[],...n?[{name:"REDIS_HOST",value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address")},{name:"REDIS_PORT",value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port")},{name:"REDIS_TLS",value:"true"}]:[],...r?[{name:"QUEUE_URL",value:d.ref("JobsQueue")}]:[],{name:"MAIL_TRANSPORT",value:"ses"}],secrets:t?[{name:"DB_USERNAME",valueFrom:d.sub("${DBSecret}:username::")},{name:"DB_PASSWORD",valueFrom:d.sub("${DBSecret}:password::")}]:[]}]},service:{desiredCount:e.desiredCount||1,healthCheck:{path:"/api/health",interval:30,timeout:5},autoScaling:{min:e.desiredCount||1,max:6,targetCPU:70}},loadBalancer:{type:"application",...e.certificateArn?{customDomain:{domain:e.domain,certificateArn:e.certificateArn}}:{},...e.originVerifySecret?{originVerifyHeader:{name:"X-Origin-Verify",value:e.originVerifySecret}}:{}}}},...t?{databases:{postgres:{engine:"postgres",version:"16",instanceClass:"db.t4g.micro",allocatedStorage:20,maxAllocatedStorage:100,multiAZ:!1,backupRetentionDays:7,deletionProtection:!0}}}:{},...n?{cache:{redis:{nodeType:"cache.t4g.micro",numCacheNodes:2,engine:"redis",engineVersion:"7.1",automaticFailoverEnabled:!0,snapshotRetentionLimit:5}}}:{},...r?{queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0,maxReceiveCount:3,receiveMessageWaitTime:20}}}:{}}}}function pg(e){let{name:t,slug:n,domain:r,apiSubdomain:i="api"}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},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:r,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:`${n}-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:`${i}.${r}`,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:r,subdomains:[`*.${r}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss"]}}}}}function yg(e){let{name:t,slug:n,domain:r}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{apiGateway:{type:"HTTP",cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"],allowHeaders:["Content-Type","Authorization"],maxAge:3600},customDomain:r?{domain:r,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:{[`${n}-users`]:{partitionKey:{name:"userId",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"EmailIndex",partitionKey:{name:"email",type:"S"},projection:"ALL"}]},[`${n}-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:r?{domain:r,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 hg(e){let{name:t,slug:n,domain:r,instanceType:i="t3.small"}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:i,ami:"ubuntu-22.04",keyPair:`${n}-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:r,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,origins:[{type:"alb",pathPattern:"/wp-content/*"}]},security:{certificate:{domain:r,subdomains:[`www.${r}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","wordpressRules"]}}}}}function Sg(e){let{name:t,slug:n,domain:r,apiDomain:i}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},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:r,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},...i?{api:{runtime:"nodejs20.x",handler:"dist/api/index.handler",memory:1024,timeout:30,events:[{type:"http",path:"/{proxy+}",method:"ANY"}]}}:{}},apiGateway:i?{type:"HTTP",customDomain:{domain:i,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:[r],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:r,subdomains:i?[i]:[],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","geoBlock"]}}}}}function Cg(e){let{name:t,slug:n,domain:r,services:i}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:3,natGateways:2}},compute:{services:i.map((s)=>({name:s.name,type:"fargate",taskDefinition:{cpu:s.cpu||"256",memory:s.memory||"512",containerDefinitions:[{name:s.name,image:`${n}-${s.name}:latest`,portMappings:[{containerPort:s.port}],healthCheck:{command:["CMD-SHELL",`curl -f http://localhost:${s.port}/health || exit 1`],interval:30,timeout:5,retries:3}}]},service:{desiredCount:s.desiredCount||2,serviceDiscovery:{enabled:!0,namespace:`${n}.local`},autoScaling:{min:2,max:10,targetCPU:70}}}))},apiGateway:{type:"HTTP",customDomain:{domain:r,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"]},routes:i.map((s)=>({path:`/${s.name}/{proxy+}`,integration:{type:"vpc-link",service:s.name}}))},databases:{dynamodb:{tables:Object.fromEntries(i.map((s)=>[`${n}-${s.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:`${n}-events`,subscriptions:i.map((s)=>({protocol:"sqs",endpoint:`${n}-${s.name}-queue`,filterPolicy:{service:[s.name]}}))}}},monitoring:{dashboard:{name:`${n}-microservices`,widgets:i.map((s)=>({type:"metric",metrics:[{service:s.name,metric:"CPUUtilization"},{service:s.name,metric:"MemoryUtilization"},{service:s.name,metric:"RequestCount"}]}))},alarms:i.flatMap((s)=>[{name:`${s.name}-high-cpu`,metric:"CPUUtilization",threshold:80,service:s.name},{name:`${s.name}-errors`,metric:"Errors",threshold:10,service:s.name}])},security:{certificate:{domain:r,validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}}}}}function Tg(e){let{name:t,slug:n,domain:r}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{apiGateway:{type:"websocket",customDomain:r?{domain:r,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:`${n}-messages`,startingPosition:"LATEST",batchSize:100}]}},databases:{dynamodb:{tables:{[`${n}-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"}]},[`${n}-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"}]},[`${n}-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:`${n}-realtime`,widgets:[{type:"metric",metrics:["WebSocketConnections","MessagesSent","IntegrationLatency"]}]}},security:{certificate:r?{domain:r,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","connectionLimit"]}}}}}function Pg(e){let{name:t,slug:n,retentionDays:r=7}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",infrastructure:{streaming:{dataStream:{name:`${n}-stream`,shardCount:2,retentionPeriod:r*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:`${n}-stream`,batchSize:1000,startingPosition:"LATEST",parallelizationFactor:10}]},transformer:{runtime:"nodejs20.x",handler:"dist/processors/transform.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${n}-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:`${n}_analytics`,workgroup:`${n}-workgroup`,outputBucket:`${n}-query-results`,tables:[{name:"raw_events",location:`s3://${n}-raw/events/`,format:"parquet",partitionKeys:["year","month","day"]},{name:"processed_events",location:`s3://${n}-processed/events/`,format:"parquet",partitionKeys:["year","month","day"]}]},glue:{crawlers:[{name:`${n}-crawler`,databaseName:`${n}_analytics`,s3Targets:[`s3://${n}-raw/`,`s3://${n}-processed/`],schedule:"cron(0 2 * * ? *)"}],jobs:[{name:`${n}-etl-job`,scriptLocation:`s3://${n}-scripts/etl.py`,role:`${n}-glue-role`,maxCapacity:10,timeout:120}]}},databases:{dynamodb:{tables:{[`${n}-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:`${n}-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:`${n}-pipeline`,widgets:[{type:"metric",metrics:["KinesisIncomingRecords","LambdaInvocations","S3ObjectsCreated","GlueJobsSucceeded"]}]},alarms:[{metric:"LambdaErrors",threshold:10,evaluationPeriods:1},{metric:"KinesisIteratorAge",threshold:60000,evaluationPeriods:2}]}}}}function wg(e){let{name:t,slug:n,domain:r,modelS3Path:i=`s3://${n}-models/`,instanceType:s="ml.t3.medium"}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},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:`${n}-inference`,modelS3Path:i,instanceType:s,initialInstanceCount:1,autoScaling:{minInstances:1,maxInstances:5,targetInvocationsPerInstance:1000}}],trainingJobs:[{name:`${n}-training`,algorithmSpecification:{trainingImage:"TO_BE_SPECIFIED",trainingInputMode:"File"},instanceType:"ml.p3.2xlarge",instanceCount:1,volumeSizeInGB:50,maxRuntimeInSeconds:86400}]}},apiGateway:{type:"HTTP",customDomain:r?{domain:r,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:`${n}-inference`,MODEL_BUCKET:`${n}-models`}},"batch-predict":{runtime:"python3.11",handler:"handlers/batchPredict.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${n}-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:{[`${n}-predictions`]:{partitionKey:{name:"requestId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0},[`${n}-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:`${n}-ml`,widgets:[{type:"metric",metrics:["SageMakerInvocations","SageMakerModelLatency","APIGatewayRequests","LambdaErrors"]}]},alarms:[{metric:"SageMakerModelLatency",threshold:1000,evaluationPeriods:2},{metric:"SageMakerInvocationErrors",threshold:10,evaluationPeriods:1}]},security:{certificate:r?{domain:r,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","apiProtection"]}}}}}function Dg(e){let{name:t,slug:n,domain:r,instanceType:i="t3.medium",minInstances:s=2,maxInstances:a=10,databaseEngine:o="mysql",sessionStore:c="redis"}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:2}},compute:{server:{instanceType:i,ami:"ubuntu-22.04",autoScaling:{min:s,max:a,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
2467
2467
  # Install Node.js or PHP/Python based on app needs
2468
2468
  # Configure application server (PM2, Nginx, Apache)
2469
2469
  # Mount EFS for shared file storage
2470
- `}},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:[r||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${n}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:r?{domain:r,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:o==="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:c==="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:`${n}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${n}-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:`${n}-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:[`${n}-app`,`${n}-nginx`,`${n}-workers`]}},security:{certificate:r?{domain:r,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:o==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...c==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function xg(e){let{name:t,slug:n,domain:r,repository:i,phpVersion:s="8.3",size:a="small",database:o=n.replace(/-/g,"_"),databasePassword:c,sslEmail:l,deployStrategy:u="push",provider:m="hetzner"}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"server",cloud:{provider:m},environments:{production:{type:"production",domain:r}},infrastructure:{compute:{mode:"server",size:a,runtime:"php",webServer:"nginx",php:{versions:[s],default:s},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:o,username:o,password:c}},sites:{main:{root:".",type:"laravel",domain:r,phpVersion:s,repository:{...i,strategy:u},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:l}}}}}function Mg(e){let{name:t,slug:n,domain:r,layers:i,phpVersion:s="8.3",architecture:a="x86_64",memory:o=1024,build:c,deploy:l=["migrate --force"],cache:u="dynamodb",scheduler:m="on",region:p="us-east-1"}=e;return{project:{name:t,slug:n,region:p},mode:"serverless",environments:{production:{type:"production",domain:r,app:{kind:"php",runtime:"provided.al2023",phpVersion:s,architecture:a,layers:i,memory:o,build:c,deploy:l,assets:"public",queues:!0,scheduler:m,cache:{driver:u},domain:r}}}}}function Og(e){return{root:e.root??"packages/ui/dist",deploy:"server",type:"static",domain:e.domain,build:e.build??"cd packages/ui && bun install && bun run build",ssl:{provider:"letsencrypt"},auth:{username:e.username??"admin",password:e.password}}}var ao=_t,oo="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function co(e){let t=e.split(".").filter(Boolean);return t.length<=2?e:t.slice(-2).join(".")}function lo(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return t>>>0}var uo=20000,mo=12000;function po(e){return uo+lo(e)%mo}function Or(e,t){let n=co(e);if(n===e)return`dashboard.${n}`;for(let r of t)if(r===n)return`dashboard.${n}`;return`dashboard.${e}`}function $r(e,t){let n=[],r=e.infrastructure?.dns?.domain;if(r&&!e.cloud?.attachTo)n.push(r);if(t&&e.environments?.[t]?.domain)n.push(e.environments[t].domain);for(let i of Object.values(e.sites??{})){let s=i;if(!s||s.redirect)continue;let a=s.domain;if(typeof a==="string")n.push(a);else if(Array.isArray(a))n.push(...a.filter((o)=>typeof o==="string"))}return n.filter((i)=>i&&!i.startsWith("dashboard."))}function go(e,t,n){if(n)return n;let r=$r(e,t),i=r[0];if(!i)return null;return Or(i,r)}function yo(e,t,n){if(n)return[n];let r=$r(e,t),i=[];for(let s of r){let a=Or(s,r);if(!i.includes(a))i.push(a)}return i}function fo(e){return Object.entries(e.sites??{}).some(([t,n])=>{if(!n)return!1;let r=n.root??"";return ho(t)||r==="ui/dist"||r.endsWith("/ui/dist")||r.endsWith("/dist/ui")})}var Br="dashboard-";function Lr(e){return Br+e.replace(/^dashboard\./,"").replace(/\./g,"-")}function ho(e){return e==="dashboard"||e.startsWith(Br)}function bo(e,t,n){if(fo(e))return[];if(e.cloud?.attachTo)return[];let r=n.password?{auth:{username:n.username||"admin",password:n.password,realm:n.realm}}:{},i=n.build===!1||n.build===void 0?{}:{build:n.build};if(n.live!==!1){let a=go(e,t,n.domain);if(!a)return[];let o=n.port??po(a),c=e.infrastructure?.appDatabase??e.infrastructure?.compute?.database,l={root:n.uiRoot,deploy:"server",domain:a,preStart:["bun install --production --no-save"],start:`bun ${oo} --box --host 127.0.0.1 --port ${o}`,port:o,cpuWeight:10,ioWeight:10,tasksMax:128,env:{APP_ENV:"production",NODE_ENV:"production",TS_CLOUD_DASHBOARD_TELEMETRY:"1",...c?.password?{TS_CLOUD_DASHBOARD_DB_PASSWORD:c.password}:{}},zeroDowntime:!1,sharedPaths:[ao],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:Lr(a),site:l}]}return yo(e,t,n.domain).map((a)=>({name:Lr(a),site:{root:n.uiRoot,deploy:"server",type:"static",domain:a,ssl:{provider:"letsencrypt"},...i,...r}}))}function Fg(e,t,n){return bo(e,t,n)[0]??null}function Zt(e,t){let n={...e};for(let r in t){let i=t[r],s=n[r];if(i===void 0)continue;if(Array.isArray(i)&&Array.isArray(s))n[r]=[...s,...i];else if(typeof i==="object"&&i!==null&&!Array.isArray(i)&&typeof s==="object"&&s!==null&&!Array.isArray(s))n[r]=Zt(s,i);else n[r]=i}return n}function Fr(e,t){return Zt(e,t)}function _g(...e){return e.reduce((t,n)=>Zt(t,n),{})}function Wg(e,t){return(n)=>{let r=e(n);if(typeof t==="function")return Fr(r,t(r,n));return Fr(r,t)}}function Ge(e){return{infrastructure:e}}function Vg(e){return Ge({monitoring:e})}function Ug(e){return Ge({security:e})}function Hg(e){return Ge({databases:e})}function jg(e){return Ge({cache:e})}function Kg(e){return Ge({cdn:e})}function qg(e){return Ge({queues:e})}Ve();import{existsSync as Qr,readFileSync as en}from"node:fs";import{homedir as Jr}from"node:os";import{join as Yr}from"node:path";function vo(){let e=process.env.AWS_ACCESS_KEY_ID,t=process.env.AWS_SECRET_ACCESS_KEY;if(!e||!t)return null;return{accessKeyId:e,secretAccessKey:t,sessionToken:process.env.AWS_SESSION_TOKEN}}function To(e){let t=e?.profile||process.env.AWS_PROFILE||"default",n=e?.credentialsFile||Yr(Jr(),".aws","credentials");if(!Qr(n))return null;try{let r=en(n,"utf-8");return Ro(r,t)}catch{return null}}function Ro(e,t){let n=e.split(`
2471
- `),r=null,i,s,a;for(let o of n){let c=o.trim();if(!c||c.startsWith("#")||c.startsWith(";"))continue;let l=c.match(/^\[([^\]]+)\]$/);if(l){if(r===t&&i&&s)return{accessKeyId:i,secretAccessKey:s,sessionToken:a};r=l[1],i=void 0,s=void 0,a=void 0;continue}if(r===t){let[u,...m]=c.split("="),p=m.join("=").trim();switch(u.trim().toLowerCase()){case"aws_access_key_id":i=p;break;case"aws_secret_access_key":s=p;break;case"aws_session_token":a=p;break}}}if(r===t&&i&&s)return{accessKeyId:i,secretAccessKey:s,sessionToken:a};return null}async function Po(e){let t=e?.timeout??1000,n="http://169.254.169.254";try{let r=await ot("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},t);if(!r.ok)return null;let i=await r.text(),s=await ot("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":i}},t);if(!s.ok)return null;let a=(await s.text()).trim(),o=await ot(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${a}`,{headers:{"X-aws-ec2-metadata-token":i}},t);if(!o.ok)return null;let c=await o.json();return{accessKeyId:c.AccessKeyId,secretAccessKey:c.SecretAccessKey,sessionToken:c.Token,expiration:new Date(c.Expiration)}}catch{return null}}async function Eo(e){let t=e?.timeout??1000,n=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,r=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,i=null;if(n)i=`http://169.254.170.2${n}`;else if(r)i=r;if(!i)return null;try{let s={},a=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(a)s.Authorization=a;let o=await ot(i,{headers:s},t);if(!o.ok)return null;let c=await o.json();return{accessKeyId:c.AccessKeyId,secretAccessKey:c.SecretAccessKey,sessionToken:c.Token,expiration:new Date(c.Expiration)}}catch{return null}}async function wo(e){let t=e?.timeout??5000,n=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,r=process.env.AWS_ROLE_ARN,i=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!n||!r)return null;try{let s=en(n,"utf-8").trim(),a=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION||"us-east-1",o=a.startsWith("us-gov")?`https://sts.${a}.amazonaws.com`:a==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${a}.amazonaws.com`,c=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:r,RoleSessionName:i,WebIdentityToken:s}),l=await ot(`${o}/?${c.toString()}`,{method:"POST"},t);if(!l.ok)return null;let u=await l.text(),m=at(u,"AccessKeyId"),p=at(u,"SecretAccessKey"),g=at(u,"SessionToken"),y=at(u,"Expiration");if(!m||!p)return null;return{accessKeyId:m,secretAccessKey:p,sessionToken:g??void 0,expiration:y?new Date(y):void 0}}catch{return null}}async function ct(e){let t=vo();if(t)return t;let n=To(e);if(n)return n;let r=await wo(e);if(r)return r;let i=await Eo(e);if(i)return i;let s=await Po(e);if(s)return s;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 oy(e){let t=null,n=null;return async()=>{if(t){if(!t.expiration)return t;let r=300000;if(t.expiration.getTime()-Date.now()>r)return t}if(n)return n;return n=ct(e).then((r)=>(t=r,n=null,r)).catch((r)=>{throw n=null,r}),n}}async function ot(e,t,n){let r=new AbortController,i=setTimeout(()=>r.abort(),n);try{let s=await fetch(e,{...t,signal:r.signal});return clearTimeout(i),s}catch(s){throw clearTimeout(i),s}}function at(e,t){let n=new RegExp(`<${t}>([^<]+)</${t}>`),r=e.match(n);return r?r[1]:null}async function Ue(e){return ct({profile:e})}function Io(e){let t=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(t)return t;let n=Yr(Jr(),".aws","config");if(Qr(n))try{let r=en(n,"utf-8"),i=e||process.env.AWS_PROFILE||"default",s=i==="default"?"[default]":`[profile ${i}]`,a=r.split(`
2472
- `),o=!1;for(let c of a){let l=c.trim();if(l.startsWith("[")){o=l===s;continue}if(o&&l.startsWith("region")){let[,u]=l.split("=");if(u)return u.trim()}}}catch{}return"us-east-1"}async function Zr(e){let t=e||await ct(),n=Io();await Ve();let i=n.startsWith("us-gov")?`https://sts.${n}.amazonaws.com`:n==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${n}.amazonaws.com`,s="Action=GetCallerIdentity&Version=2011-06-15",a=V({method:"POST",url:i,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...t,service:"sts",region:n}),o=await fetch(a.url,{method:a.method,headers:a.headers,body:a.body});if(!o.ok)throw Error(`Failed to get account ID: ${await o.text()}`);let c=await o.text(),l=at(c,"Account");if(!l)throw Error("Failed to parse account ID from response");return l}await Ve();class Do{profile;credentials=null;region;constructor(e="us-east-1",t="default"){this.profile=t;this.region=e}async init(){if(this.credentials=await Ue(this.profile),this.credentials.region)this.region=this.credentials.region}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async request(e,t){let n=await this.ensureCredentials(),r={Action:e,Version:"2010-05-15",...tn(t)},i=new URLSearchParams(r).toString(),a=await(await De({method:"POST",url:`https://cloudformation.${this.region}.amazonaws.com/`,service:"cloudformation",region:this.region,headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,sessionToken:n.sessionToken})).text();return No(a)}async createStack(e){let t={StackName:e.stackName};if(e.templateBody)t.TemplateBody=e.templateBody;else if(e.templateURL)t.TemplateURL=e.templateURL;else throw Error("Either templateBody or templateURL must be provided");if(e.parameters)for(let[i,[s,a]]of Object.entries(e.parameters).entries())t[`Parameters.member.${i+1}.ParameterKey`]=s,t[`Parameters.member.${i+1}.ParameterValue`]=a;if(e.capabilities)for(let[i,s]of e.capabilities.entries())t[`Capabilities.member.${i+1}`]=s;if(e.tags)for(let[i,[s,a]]of Object.entries(e.tags).entries())t[`Tags.member.${i+1}.Key`]=s,t[`Tags.member.${i+1}.Value`]=a;if(e.timeoutInMinutes)t.TimeoutInMinutes=e.timeoutInMinutes;if(e.onFailure)t.OnFailure=e.onFailure;let n=await this.request("CreateStack",t);return(n?.CreateStackResult||n?.CreateStackResponse?.CreateStackResult||n)?.StackId}async updateStack(e){let t={StackName:e.stackName};if(e.templateBody)t.TemplateBody=e.templateBody;else if(e.templateURL)t.TemplateURL=e.templateURL;if(e.parameters)for(let[i,[s,a]]of Object.entries(e.parameters).entries())t[`Parameters.member.${i+1}.ParameterKey`]=s,t[`Parameters.member.${i+1}.ParameterValue`]=a;if(e.capabilities)for(let[i,s]of e.capabilities.entries())t[`Capabilities.member.${i+1}`]=s;if(e.tags)for(let[i,[s,a]]of Object.entries(e.tags).entries())t[`Tags.member.${i+1}.Key`]=s,t[`Tags.member.${i+1}.Value`]=a;let n=await this.request("UpdateStack",t);return(n?.UpdateStackResult||n?.UpdateStackResponse?.UpdateStackResult||n)?.StackId}async deleteStack(e){await this.request("DeleteStack",{StackName:e})}async describeStack(e){let t=await this.request("DescribeStacks",{StackName:e}),r=(t?.DescribeStacksResult||t?.DescribeStacksResponse?.DescribeStacksResult||t)?.Stacks?.member,i=Array.isArray(r)?r[0]:r;if(!i)throw Error(`Stack ${e} not found`);return xo(i)}async listStacks(e){let t={};if(e)for(let[r,i]of e.entries())t[`StackStatusFilter.member.${r+1}`]=i;let n=await this.request("ListStacks",t);return ko(n)}async describeStackEvents(e){let t=await this.request("DescribeStackEvents",{StackName:e});return Mo(t)}async waitForStack(e,t,n){let s=0,a=null;while(s<360){s++;let o=await this.describeStack(e);if(n)try{let c=await this.describeStackEvents(e),l=[];if(a){for(let u of c){if(u.EventId===a)break;l.push(u)}l.reverse()}else if(c.length>0)l=[c[0]];for(let u of l)n(u);if(c.length>0)a=c[0].EventId}catch{}if(o.StackStatus&&t.includes(o.StackStatus))return o;if(o.StackStatus?.includes("FAILED")||o.StackStatus?.includes("ROLLBACK"))throw Error(`Stack reached failed state: ${o.StackStatus}
2473
- Reason: ${o.StackStatusReason||"Unknown"}`);await new Promise((c)=>setTimeout(c,5000))}throw Error(`Timeout waiting for stack ${e} to complete`)}async waitForStackWithProgress(e,t,n){let i={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[t];if(!i)throw Error(`Unknown waiter: ${t}`);return this.waitForStack(e,i,n)}async createChangeSet(e){let t={StackName:e.stackName,ChangeSetName:e.changeSetName,ChangeSetType:"UPDATE"};if(e.templateBody)t.TemplateBody=e.templateBody;else if(e.templateURL)t.TemplateURL=e.templateURL;if(e.parameters)for(let[r,[i,s]]of Object.entries(e.parameters).entries())t[`Parameters.member.${r+1}.ParameterKey`]=i,t[`Parameters.member.${r+1}.ParameterValue`]=s;if(e.capabilities)for(let[r,i]of e.capabilities.entries())t[`Capabilities.member.${r+1}`]=i;return(await this.request("CreateChangeSet",t)).ChangeSetId}async executeChangeSet(e,t){await this.request("ExecuteChangeSet",{ChangeSetName:e,StackName:t})}async describeStacks(e){let t=typeof e==="string"?e:e.stackName;try{return{Stacks:[await this.describeStack(t)]}}catch{return{Stacks:[]}}}async getStackOutputs(e){let t=await this.request("DescribeStacks",{StackName:e}),r=(t?.DescribeStacksResult||t?.DescribeStacksResponse?.DescribeStacksResult||t)?.Stacks?.member,i=Array.isArray(r)?r[0]:r;if(!i)return{};let s={},a=i.Outputs?.member;if(a){let o=Array.isArray(a)?a:[a];for(let c of o)if(c.OutputKey&&c.OutputValue)s[c.OutputKey]=c.OutputValue}return s}}function tn(e,t=""){let n={};for(let[r,i]of Object.entries(e)){let s=t?`${t}.${r}`:r;if(Array.isArray(i))i.forEach((a,o)=>{if(typeof a==="object")Object.assign(n,tn(a,`${s}.${o+1}`));else n[`${s}.${o+1}`]=String(a)});else if(typeof i==="object"&&i!==null)Object.assign(n,tn(i,s));else if(i!==void 0&&i!==null)n[s]=String(i)}return n}function No(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function t(i,s,a){let o=1,c=a,l=`<${s}`,u=`</${s}>`;while(c<i.length&&o>0){let m=i.indexOf(l,c),p=i.indexOf(u,c);if(p===-1)return-1;if(m!==-1&&m<p){let g=i[m+l.length];if(g===">"||g===" "||g==="/"){let y=i.indexOf(">",m);if(y!==-1&&i[y-1]==="/")c=y+1;else o++,c=y+1}else c=m+l.length}else{if(o--,o===0)return p;c=p+u.length}}return-1}function n(i,s){while(s<i.length&&/\s/.test(i[s]))s++;if(s>=i.length||i[s]!=="<"){let h=i.indexOf("<",s);if(h===-1)return{value:i.slice(s).trim(),end:i.length};return{value:i.slice(s,h).trim(),end:h}}if(i[s+1]==="/")return{value:void 0,end:s};let a=i.slice(s).match(/^<(\w+)([^>]*?)\/?>/);if(!a)return{value:void 0,end:s+1};let o=a[1];if(a[0].endsWith("/>"))return{value:"",end:s+a[0].length};let l=s+a[0].length,u=`</${o}>`,m=t(i,o,l);if(m===-1)return{value:void 0,end:s+a[0].length};let p=i.slice(l,m).trim();if(!p.includes("<"))return{value:p,end:m+u.length};let g={},y=l;while(y<m){while(y<m&&/\s/.test(i[y]))y++;if(y>=m)break;if(i[y]!=="<"||i[y+1]==="/")break;let h=i.slice(y).match(/^<(\w+)/);if(!h)break;let b=h[1],v=n(i,y);if(v.value===void 0){y++;continue}if(b==="member"||g[b]!==void 0){if(!Array.isArray(g[b]))g[b]=g[b]!==void 0?[g[b]]:[];g[b].push(v.value)}else g[b]=v.value;y=v.end}return{value:g,end:m+u.length}}return n(e,0).value||{}}function xo(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function ko(e){let n=(e?.ListStacksResult||e?.ListStacksResponse?.ListStacksResult||e)?.StackSummaries?.member;if(!n)return[];return(Array.isArray(n)?n:[n]).map((i)=>({StackName:i.StackName||"",StackId:i.StackId,StackStatus:i.StackStatus,CreationTime:i.CreationTime,LastUpdatedTime:i.LastUpdatedTime,StackStatusReason:i.StackStatusReason,Description:i.Description}))}function Mo(e){let n=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!n)return[];return(Array.isArray(n)?n:[n]).map((i)=>({StackId:i.StackId||"",EventId:i.EventId||"",StackName:i.StackName||"",LogicalResourceId:i.LogicalResourceId||"",PhysicalResourceId:i.PhysicalResourceId,ResourceType:i.ResourceType||"",Timestamp:i.Timestamp||"",ResourceStatus:i.ResourceStatus||"",ResourceStatusReason:i.ResourceStatusReason}))}await Ve();var Lo=5242880,nn=5242880;var Oo=5242880;class rn{region;endpoint;forcePathStyle;credentials;credentialOptions;retryOptions;constructor(e={}){this.region=e.region||process.env.AWS_REGION||"us-east-1",this.endpoint=e.endpoint||`https://s3.${this.region}.amazonaws.com`,this.forcePathStyle=e.forcePathStyle||!1,this.credentials=e.credentials,this.credentialOptions=e.credentialOptions,this.retryOptions=e.retryOptions||{}}async getCredentials(){if(this.credentials)return this.credentials;return ct(this.credentialOptions)}buildUrl(e,t){let n=t?encodeURIComponent(t).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return t?`${this.endpoint}/${e}/${n}`:`${this.endpoint}/${e}`;let r=new URL(this.endpoint);return r.hostname=`${e}.${r.hostname}`,t?`${r.origin}/${n}`:r.origin}async get(e,t,n={}){let r=await this.getCredentials(),i=this.buildUrl(e,t),s={};if(n.range)s.Range=n.range;if(n.ifModifiedSince)s["If-Modified-Since"]=n.ifModifiedSince.toUTCString();if(n.ifMatch)s["If-Match"]=n.ifMatch;if(n.ifNoneMatch)s["If-None-Match"]=n.ifNoneMatch;let a=new URL(i);if(n.responseContentType)a.searchParams.set("response-content-type",n.responseContentType);if(n.responseContentDisposition)a.searchParams.set("response-content-disposition",n.responseContentDisposition);let o=V({method:"GET",url:a.toString(),headers:s,...r,service:"s3",region:this.region}),c=await fetch(o.url,{method:o.method,headers:o.headers});if(!c.ok&&c.status!==304){let l=await c.text();throw new q(`Failed to get object: ${l}`,c.status,e,t)}return c}async getText(e,t,n={}){return(await this.get(e,t,n)).text()}async getJSON(e,t,n={}){return(await this.get(e,t,n)).json()}async getBuffer(e,t,n={}){return(await this.get(e,t,n)).arrayBuffer()}async put(e,t,n,r={}){let i,s;if(typeof n==="string")i=new TextEncoder().encode(n).length,s=n;else if(n instanceof ArrayBuffer)i=n.byteLength,s=n;else if(n instanceof Uint8Array)i=n.byteLength,s=n;else if(n instanceof Blob)i=n.size,s=n;else return this.uploadMultipart(e,t,n,{...r,partSize:nn});if(i>Oo){let a=Fo(s).stream();return this.uploadMultipart(e,t,a,{...r,partSize:nn})}return this.putSimple(e,t,s,i,r)}async putSimple(e,t,n,r,i){let s=await this.getCredentials(),a=this.buildUrl(e,t),o={"Content-Length":String(r),"Content-Type":i.contentType||Xr(t)};if(i.contentEncoding)o["Content-Encoding"]=i.contentEncoding;if(i.cacheControl)o["Cache-Control"]=i.cacheControl;if(i.contentDisposition)o["Content-Disposition"]=i.contentDisposition;if(i.storageClass)o["x-amz-storage-class"]=i.storageClass;if(i.serverSideEncryption)o["x-amz-server-side-encryption"]=i.serverSideEncryption;if(i.acl)o["x-amz-acl"]=i.acl;if(i.tagging)o["x-amz-tagging"]=i.tagging;if(i.metadata)for(let[p,g]of Object.entries(i.metadata))o[`x-amz-meta-${p.toLowerCase()}`]=g;let c;if(typeof n==="string")c=n;else if(n instanceof Blob)c=await n.text();else c=new TextDecoder().decode(n instanceof ArrayBuffer?new Uint8Array(n):n);let l=V({method:"PUT",url:a,headers:o,body:c,...s,service:"s3",region:this.region}),u=await fetch(l.url,{method:l.method,headers:l.headers,body:n});if(!u.ok){let p=await u.text();throw new q(`Failed to put object: ${p}`,u.status,e,t)}return{etag:(u.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,t){let n=await this.getCredentials(),r=this.buildUrl(e,t),i=V({method:"DELETE",url:r,...n,service:"s3",region:this.region}),s=await fetch(i.url,{method:i.method,headers:i.headers});if(!s.ok&&s.status!==204){let a=await s.text();throw new q(`Failed to delete object: ${a}`,s.status,e,t)}}async deleteMany(e,t){let n=await this.getCredentials(),r=`${this.buildUrl(e)}?delete`,s=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${t.map((y)=>`<Object><Key>${Bo(y)}</Key></Object>`).join("")}</Delete>`,a=V({method:"POST",url:r,headers:{"Content-Type":"application/xml"},body:s,...n,service:"s3",region:this.region}),o=await fetch(a.url,{method:a.method,headers:a.headers,body:s});if(!o.ok){let y=await o.text();throw new q(`Failed to delete objects: ${y}`,o.status,e)}let c=await o.text(),l=[],u=[],m=/<Deleted><Key>([^<]+)<\/Key>/g,p;while((p=m.exec(c))!==null)l.push(p[1]);let g=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((p=g.exec(c))!==null)u.push({key:p[1],error:`${p[2]}: ${p[3]}`});return{deleted:l,errors:u}}async list(e,t={}){let n=await this.getCredentials(),r=new URL(this.buildUrl(e));if(r.searchParams.set("list-type","2"),t.prefix)r.searchParams.set("prefix",t.prefix);if(t.delimiter)r.searchParams.set("delimiter",t.delimiter);if(t.maxKeys)r.searchParams.set("max-keys",String(t.maxKeys));if(t.continuationToken)r.searchParams.set("continuation-token",t.continuationToken);if(t.startAfter)r.searchParams.set("start-after",t.startAfter);let i=V({method:"GET",url:r.toString(),...n,service:"s3",region:this.region}),s=await fetch(i.url,{method:i.method,headers:i.headers});if(!s.ok){let o=await s.text();throw new q(`Failed to list objects: ${o}`,s.status,e)}let a=await s.text();return $o(a)}async*listAll(e,t={}){let n;do{let r=await this.list(e,{...t,continuationToken:n});for(let i of r.contents)yield i;n=r.nextContinuationToken}while(n)}async head(e,t){let n=await this.getCredentials(),r=this.buildUrl(e,t),i=V({method:"HEAD",url:r,...n,service:"s3",region:this.region}),s=await fetch(i.url,{method:i.method,headers:i.headers});if(s.status===404)return null;if(!s.ok){let o=await s.text();throw new q(`Failed to head object: ${o}`,s.status,e,t)}let a={};return s.headers.forEach((o,c)=>{if(c.toLowerCase().startsWith("x-amz-meta-"))a[c.slice(11)]=o}),{contentLength:Number(s.headers.get("Content-Length")||0),contentType:s.headers.get("Content-Type")||"application/octet-stream",etag:(s.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(s.headers.get("Last-Modified")||0),metadata:a,storageClass:s.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:s.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,t){return await this.head(e,t)!==null}async copy(e,t,n,r,i={}){let s=await this.getCredentials(),a=this.buildUrl(n,r),o={"x-amz-copy-source":`/${e}/${encodeURIComponent(t)}`};if(i.metadataDirective)o["x-amz-metadata-directive"]=i.metadataDirective;if(i.contentType)o["Content-Type"]=i.contentType;if(i.storageClass)o["x-amz-storage-class"]=i.storageClass;if(i.acl)o["x-amz-acl"]=i.acl;if(i.metadata)for(let[g,y]of Object.entries(i.metadata))o[`x-amz-meta-${g.toLowerCase()}`]=y;let c=V({method:"PUT",url:a,headers:o,...s,service:"s3",region:this.region}),l=await fetch(c.url,{method:c.method,headers:c.headers});if(!l.ok){let g=await l.text();throw new q(`Failed to copy object: ${g}`,l.status,n,r)}let m=(await l.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:m?m[1]:""}}async getPresignedUrl(e,t,n={}){let r=await this.getCredentials(),i=this.buildUrl(e,t);return Vr({url:i,method:n.method||"GET",expiresIn:n.expiresIn||3600,...r,service:"s3",region:this.region})}async uploadMultipart(e,t,n,r={}){let i=await this.getCredentials(),s=Math.max(r.partSize||nn,Lo),a,o;if(n instanceof ReadableStream)a=n;else if(n instanceof Blob)a=n.stream(),o=n.size;else{let u=new Blob([n]);a=u.stream(),o=u.size}let{uploadId:c,baseUrl:l}=await this.initiateMultipartUpload(e,t,r);try{let u=await this.uploadParts(e,t,l,c,a,s,i,o,r.concurrency||4,r.onProgress);return await this.completeMultipartUpload(e,t,l,c,u)}catch(u){throw await this.abortMultipartUpload(e,t,c,l).catch(()=>{}),u}}async initiateMultipartUpload(e,t,n){let r=await this.getCredentials(),i=this.buildUrl(e,t),s=`${i}?uploads`,a={"Content-Type":n.contentType||Xr(t)};if(n.storageClass)a["x-amz-storage-class"]=n.storageClass;if(n.serverSideEncryption)a["x-amz-server-side-encryption"]=n.serverSideEncryption;if(n.acl)a["x-amz-acl"]=n.acl;if(n.metadata)for(let[p,g]of Object.entries(n.metadata))a[`x-amz-meta-${p.toLowerCase()}`]=g;let o=V({method:"POST",url:s,headers:a,...r,service:"s3",region:this.region}),c=await fetch(o.url,{method:o.method,headers:o.headers});if(!c.ok){let p=await c.text();throw new q(`Failed to initiate multipart upload: ${p}`,c.status,e,t)}let u=(await c.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!u)throw new q("Failed to parse upload ID from response",0,e,t);let m=i;if(c.url)try{let p=new URL(c.url);p.search="",m=p.toString()}catch{}return{uploadId:u[1],baseUrl:m}}async uploadParts(e,t,n,r,i,s,a,o,c,l){let u=[],m=i.getReader(),p=1,g=new Uint8Array(0),y=0,h=o?Math.ceil(o/s):void 0,b=new Map,v=async(A,R)=>{let P=`${n}?partNumber=${R}&uploadId=${encodeURIComponent(r)}`,E={"Content-Length":String(A.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},w=V({method:"PUT",url:P,headers:E,...a,service:"s3",region:this.region}),I=await fetch(w.url,{method:w.method,headers:w.headers,body:A,redirect:"error"});if(!I.ok){let k=await I.text();throw new q(`Failed to upload part ${R}: ${k}`,I.status,e,t)}let D=(I.headers.get("ETag")||"").replace(/"/g,"");if(!D)throw new q(`Missing ETag for part ${R}`,I.status,e,t);return{partNumber:R,etag:D}},T=async()=>{let A=await Promise.race(b.values());b.delete(A.partNumber),u.push(A)};while(!0){let{done:A,value:R}=await m.read();if(R){let P=new Uint8Array(g.length+R.length);P.set(g),P.set(R,g.length),g=P}while(g.length>=s||A&&g.length>0){let P=g.slice(0,s);g=g.slice(s);let E=p++;if(b.size>=c)await T();if(b.set(E,v(P,E)),y+=P.byteLength,l)l({loaded:y,total:o||y,part:E,totalParts:h||E})}if(A)break}while(b.size>0)await T();return u.sort((A,R)=>A.partNumber-R.partNumber),u}async completeMultipartUpload(e,t,n,r,i){let s=await this.getCredentials(),a=`${n}?uploadId=${encodeURIComponent(r)}`,c=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${i.map((y)=>`<Part><PartNumber>${y.partNumber}</PartNumber><ETag>"${y.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,l=V({method:"POST",url:a,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 y=await u.text();throw new q(`Failed to complete multipart upload: ${y}`,u.status,e,t)}let p=(await u.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:p?p[1]:""}}async abortMultipartUpload(e,t,n,r){let i=await this.getCredentials(),s=`${r??this.buildUrl(e,t)}?uploadId=${encodeURIComponent(n)}`,a=V({method:"DELETE",url:s,...i,service:"s3",region:this.region});await fetch(a.url,{method:a.method,headers:a.headers})}async emptyAndDeleteBucket(e){let n=[];for await(let a of this.listAll(e,{}))if(n.push(a.key),n.length>=1000)await this.deleteMany(e,n),n=[];if(n.length>0)await this.deleteMany(e,n);let r=await this.getCredentials(),i=this.buildUrl(e),s=V({method:"DELETE",url:i,...r,service:"s3",region:this.region});await fetch(s.url,{method:s.method,headers:s.headers})}}class q extends Error{statusCode;bucket;key;constructor(e,t,n,r){super(e);this.statusCode=t;this.bucket=n;this.key=r;this.name="S3Error"}}function $o(e){let t=[],n=[],r=/<Contents>([\s\S]*?)<\/Contents>/g,i;while((i=r.exec(e))!==null){let a=i[1];t.push({key:ne(a,"Key")||"",lastModified:new Date(ne(a,"LastModified")||0),etag:(ne(a,"ETag")||"").replace(/"/g,""),size:Number(ne(a,"Size")||0),storageClass:ne(a,"StorageClass")||"STANDARD"})}let s=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((i=s.exec(e))!==null)n.push(i[1]);return{contents:t,commonPrefixes:n,isTruncated:ne(e,"IsTruncated")==="true",continuationToken:ne(e,"ContinuationToken")||void 0,nextContinuationToken:ne(e,"NextContinuationToken")||void 0,keyCount:Number(ne(e,"KeyCount")||0),maxKeys:Number(ne(e,"MaxKeys")||1000),prefix:ne(e,"Prefix")||void 0,delimiter:ne(e,"Delimiter")||void 0}}function ne(e,t){let n=new RegExp(`<${t}>([^<]*)</${t}>`),r=e.match(n);return r?r[1]:null}function Bo(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function Xr(e){let t=e.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"}[t||""]||"application/octet-stream"}function Fo(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function Go(e){return new rn(e)}await Ve();class _o{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await Ue(this.profile)}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async createInvalidation(e){let t=await this.ensureCredentials(),n=e.callerReference||`invalidation-${Date.now()}`,r=`<?xml version="1.0" encoding="UTF-8"?>
2470
+ `}},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:[r||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${n}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:r?{domain:r,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:o==="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:c==="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:`${n}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${n}-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:`${n}-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:[`${n}-app`,`${n}-nginx`,`${n}-workers`]}},security:{certificate:r?{domain:r,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:o==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...c==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function xg(e){let{name:t,slug:n,domain:r,repository:i,phpVersion:s="8.3",size:a="small",database:o=n.replace(/-/g,"_"),databasePassword:c,sslEmail:l,deployStrategy:u="push",provider:m="hetzner"}=e;return{project:{name:t,slug:n,region:"us-east-1"},mode:"server",cloud:{provider:m},environments:{production:{type:"production",domain:r}},infrastructure:{compute:{mode:"server",size:a,runtime:"php",webServer:"nginx",php:{versions:[s],default:s},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:o,username:o,password:c}},sites:{main:{root:".",type:"laravel",domain:r,phpVersion:s,repository:{...i,strategy:u},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:l}}}}}function Mg(e){let{name:t,slug:n,domain:r,layers:i,phpVersion:s="8.3",architecture:a="x86_64",memory:o=1024,build:c,deploy:l=["migrate --force"],cache:u="dynamodb",scheduler:m="on",region:p="us-east-1"}=e;return{project:{name:t,slug:n,region:p},mode:"serverless",environments:{production:{type:"production",domain:r,app:{kind:"php",runtime:"provided.al2023",phpVersion:s,architecture:a,layers:i,memory:o,build:c,deploy:l,assets:"public",queues:!0,scheduler:m,cache:{driver:u},domain:r}}}}}function Og(e){return{root:e.root??"packages/ui/dist",deploy:"server",type:"static",domain:e.domain,build:e.build??"cd packages/ui && bun install && bun run build",ssl:{provider:"letsencrypt"},auth:{username:e.username??"admin",password:e.password}}}var ao=_t,oo="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function co(e){let t=e.split(".").filter(Boolean);return t.length<=2?e:t.slice(-2).join(".")}function lo(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619);return t>>>0}var uo=20000,mo=12000;function po(e){return uo+lo(e)%mo}function Or(e,t){let n=co(e);if(n===e)return`dashboard.${n}`;for(let r of t)if(r===n)return`dashboard.${n}`;return`dashboard.${e}`}function $r(e,t){let n=[],r=e.infrastructure?.dns?.domain;if(r&&!e.cloud?.attachTo)n.push(r);if(t&&e.environments?.[t]?.domain)n.push(e.environments[t].domain);for(let i of Object.values(e.sites??{})){let s=i;if(!s||s.redirect)continue;let a=s.domain;if(typeof a==="string")n.push(a);else if(Array.isArray(a))n.push(...a.filter((o)=>typeof o==="string"))}return n.filter((i)=>i&&!i.startsWith("dashboard."))}function go(e,t,n){if(n)return n;let r=$r(e,t),i=r[0];if(!i)return null;return Or(i,r)}function yo(e,t,n){if(n)return[n];let r=$r(e,t),i=[];for(let s of r){let a=Or(s,r);if(!i.includes(a))i.push(a)}return i}function fo(e){return Object.entries(e.sites??{}).some(([t,n])=>{if(!n)return!1;let r=n.root??"";return ho(t)||r==="ui/dist"||r.endsWith("/ui/dist")||r.endsWith("/dist/ui")})}var Br="dashboard-";function Lr(e){return Br+e.replace(/^dashboard\./,"").replace(/\./g,"-")}function ho(e){return e==="dashboard"||e.startsWith(Br)}function bo(e,t,n){if(fo(e))return[];if(e.cloud?.attachTo)return[];let r=n.password?{auth:{username:n.username||"admin",password:n.password,realm:n.realm}}:{},i=n.build===!1||n.build===void 0?{}:{build:n.build};if(n.live!==!1){let a=go(e,t,n.domain);if(!a)return[];let o=n.port??po(a),c=e.infrastructure?.appDatabase??e.infrastructure?.compute?.database,l={root:n.uiRoot,deploy:"server",domain:a,preStart:["bun install --production --no-save"],start:`bun ${oo} --box --host 127.0.0.1 --port ${o}`,port:o,cpuWeight:10,ioWeight:10,tasksMax:128,env:{APP_ENV:"production",NODE_ENV:"production",TS_CLOUD_DASHBOARD_TELEMETRY:"1",...c?.password?{TS_CLOUD_DASHBOARD_DB_PASSWORD:c.password}:{}},zeroDowntime:!1,sharedPaths:[ao],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:Lr(a),site:l}]}return yo(e,t,n.domain).map((a)=>({name:Lr(a),site:{root:n.uiRoot,deploy:"server",type:"static",domain:a,ssl:{provider:"letsencrypt"},...i,...r}}))}function Fg(e,t,n){return bo(e,t,n)[0]??null}function Zt(e,t){let n={...e};for(let r in t){let i=t[r],s=n[r];if(i===void 0)continue;if(Array.isArray(i)&&Array.isArray(s))n[r]=[...s,...i];else if(typeof i==="object"&&i!==null&&!Array.isArray(i)&&typeof s==="object"&&s!==null&&!Array.isArray(s))n[r]=Zt(s,i);else n[r]=i}return n}function Fr(e,t){return Zt(e,t)}function _g(...e){return e.reduce((t,n)=>Zt(t,n),{})}function Wg(e,t){return(n)=>{let r=e(n);if(typeof t==="function")return Fr(r,t(r,n));return Fr(r,t)}}function We(e){return{infrastructure:e}}function Vg(e){return We({monitoring:e})}function Ug(e){return We({security:e})}function Hg(e){return We({databases:e})}function jg(e){return We({cache:e})}function Kg(e){return We({cdn:e})}function qg(e){return We({queues:e})}He();import{existsSync as Qr,readFileSync as en}from"node:fs";import{homedir as Jr}from"node:os";import{join as Yr}from"node:path";function vo(){let e=process.env.AWS_ACCESS_KEY_ID,t=process.env.AWS_SECRET_ACCESS_KEY;if(!e||!t)return null;return{accessKeyId:e,secretAccessKey:t,sessionToken:process.env.AWS_SESSION_TOKEN}}function To(e){let t=e?.profile||process.env.AWS_PROFILE||"default",n=e?.credentialsFile||Yr(Jr(),".aws","credentials");if(!Qr(n))return null;try{let r=en(n,"utf-8");return Ro(r,t)}catch{return null}}function Ro(e,t){let n=e.split(`
2471
+ `),r=null,i,s,a;for(let o of n){let c=o.trim();if(!c||c.startsWith("#")||c.startsWith(";"))continue;let l=c.match(/^\[([^\]]+)\]$/);if(l){if(r===t&&i&&s)return{accessKeyId:i,secretAccessKey:s,sessionToken:a};r=l[1],i=void 0,s=void 0,a=void 0;continue}if(r===t){let[u,...m]=c.split("="),p=m.join("=").trim();switch(u.trim().toLowerCase()){case"aws_access_key_id":i=p;break;case"aws_secret_access_key":s=p;break;case"aws_session_token":a=p;break}}}if(r===t&&i&&s)return{accessKeyId:i,secretAccessKey:s,sessionToken:a};return null}async function Po(e){let t=e?.timeout??1000,n="http://169.254.169.254";try{let r=await ct("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},t);if(!r.ok)return null;let i=await r.text(),s=await ct("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":i}},t);if(!s.ok)return null;let a=(await s.text()).trim(),o=await ct(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${a}`,{headers:{"X-aws-ec2-metadata-token":i}},t);if(!o.ok)return null;let c=await o.json();return{accessKeyId:c.AccessKeyId,secretAccessKey:c.SecretAccessKey,sessionToken:c.Token,expiration:new Date(c.Expiration)}}catch{return null}}async function Eo(e){let t=e?.timeout??1000,n=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,r=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,i=null;if(n)i=`http://169.254.170.2${n}`;else if(r)i=r;if(!i)return null;try{let s={},a=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(a)s.Authorization=a;let o=await ct(i,{headers:s},t);if(!o.ok)return null;let c=await o.json();return{accessKeyId:c.AccessKeyId,secretAccessKey:c.SecretAccessKey,sessionToken:c.Token,expiration:new Date(c.Expiration)}}catch{return null}}async function wo(e){let t=e?.timeout??5000,n=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,r=process.env.AWS_ROLE_ARN,i=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!n||!r)return null;try{let s=en(n,"utf-8").trim(),a=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION||"us-east-1",o=a.startsWith("us-gov")?`https://sts.${a}.amazonaws.com`:a==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${a}.amazonaws.com`,c=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:r,RoleSessionName:i,WebIdentityToken:s}),l=await ct(`${o}/?${c.toString()}`,{method:"POST"},t);if(!l.ok)return null;let u=await l.text(),m=ot(u,"AccessKeyId"),p=ot(u,"SecretAccessKey"),g=ot(u,"SessionToken"),y=ot(u,"Expiration");if(!m||!p)return null;return{accessKeyId:m,secretAccessKey:p,sessionToken:g??void 0,expiration:y?new Date(y):void 0}}catch{return null}}async function lt(e){let t=vo();if(t)return t;let n=To(e);if(n)return n;let r=await wo(e);if(r)return r;let i=await Eo(e);if(i)return i;let s=await Po(e);if(s)return s;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 oy(e){let t=null,n=null;return async()=>{if(t){if(!t.expiration)return t;let r=300000;if(t.expiration.getTime()-Date.now()>r)return t}if(n)return n;return n=lt(e).then((r)=>(t=r,n=null,r)).catch((r)=>{throw n=null,r}),n}}async function ct(e,t,n){let r=new AbortController,i=setTimeout(()=>r.abort(),n);try{let s=await fetch(e,{...t,signal:r.signal});return clearTimeout(i),s}catch(s){throw clearTimeout(i),s}}function ot(e,t){let n=new RegExp(`<${t}>([^<]+)</${t}>`),r=e.match(n);return r?r[1]:null}async function je(e){return lt({profile:e})}function Io(e){let t=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(t)return t;let n=Yr(Jr(),".aws","config");if(Qr(n))try{let r=en(n,"utf-8"),i=e||process.env.AWS_PROFILE||"default",s=i==="default"?"[default]":`[profile ${i}]`,a=r.split(`
2472
+ `),o=!1;for(let c of a){let l=c.trim();if(l.startsWith("[")){o=l===s;continue}if(o&&l.startsWith("region")){let[,u]=l.split("=");if(u)return u.trim()}}}catch{}return"us-east-1"}async function Zr(e){let t=e||await lt(),n=Io();await He();let i=n.startsWith("us-gov")?`https://sts.${n}.amazonaws.com`:n==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${n}.amazonaws.com`,s="Action=GetCallerIdentity&Version=2011-06-15",a=H({method:"POST",url:i,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...t,service:"sts",region:n}),o=await fetch(a.url,{method:a.method,headers:a.headers,body:a.body});if(!o.ok)throw Error(`Failed to get account ID: ${await o.text()}`);let c=await o.text(),l=ot(c,"Account");if(!l)throw Error("Failed to parse account ID from response");return l}await He();class Do{profile;credentials=null;region;constructor(e="us-east-1",t="default"){this.profile=t;this.region=e}async init(){if(this.credentials=await je(this.profile),this.credentials.region)this.region=this.credentials.region}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async request(e,t){let n=await this.ensureCredentials(),r={Action:e,Version:"2010-05-15",...tn(t)},i=new URLSearchParams(r).toString(),a=await(await Ne({method:"POST",url:`https://cloudformation.${this.region}.amazonaws.com/`,service:"cloudformation",region:this.region,headers:{"Content-Type":"application/x-www-form-urlencoded"},body:i,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,sessionToken:n.sessionToken})).text();return No(a)}async createStack(e){let t={StackName:e.stackName};if(e.templateBody)t.TemplateBody=e.templateBody;else if(e.templateURL)t.TemplateURL=e.templateURL;else throw Error("Either templateBody or templateURL must be provided");if(e.parameters)for(let[i,[s,a]]of Object.entries(e.parameters).entries())t[`Parameters.member.${i+1}.ParameterKey`]=s,t[`Parameters.member.${i+1}.ParameterValue`]=a;if(e.capabilities)for(let[i,s]of e.capabilities.entries())t[`Capabilities.member.${i+1}`]=s;if(e.tags)for(let[i,[s,a]]of Object.entries(e.tags).entries())t[`Tags.member.${i+1}.Key`]=s,t[`Tags.member.${i+1}.Value`]=a;if(e.timeoutInMinutes)t.TimeoutInMinutes=e.timeoutInMinutes;if(e.onFailure)t.OnFailure=e.onFailure;let n=await this.request("CreateStack",t);return(n?.CreateStackResult||n?.CreateStackResponse?.CreateStackResult||n)?.StackId}async updateStack(e){let t={StackName:e.stackName};if(e.templateBody)t.TemplateBody=e.templateBody;else if(e.templateURL)t.TemplateURL=e.templateURL;if(e.parameters)for(let[i,[s,a]]of Object.entries(e.parameters).entries())t[`Parameters.member.${i+1}.ParameterKey`]=s,t[`Parameters.member.${i+1}.ParameterValue`]=a;if(e.capabilities)for(let[i,s]of e.capabilities.entries())t[`Capabilities.member.${i+1}`]=s;if(e.tags)for(let[i,[s,a]]of Object.entries(e.tags).entries())t[`Tags.member.${i+1}.Key`]=s,t[`Tags.member.${i+1}.Value`]=a;let n=await this.request("UpdateStack",t);return(n?.UpdateStackResult||n?.UpdateStackResponse?.UpdateStackResult||n)?.StackId}async deleteStack(e){await this.request("DeleteStack",{StackName:e})}async describeStack(e){let t=await this.request("DescribeStacks",{StackName:e}),r=(t?.DescribeStacksResult||t?.DescribeStacksResponse?.DescribeStacksResult||t)?.Stacks?.member,i=Array.isArray(r)?r[0]:r;if(!i)throw Error(`Stack ${e} not found`);return xo(i)}async listStacks(e){let t={};if(e)for(let[r,i]of e.entries())t[`StackStatusFilter.member.${r+1}`]=i;let n=await this.request("ListStacks",t);return ko(n)}async describeStackEvents(e){let t=await this.request("DescribeStackEvents",{StackName:e});return Mo(t)}async waitForStack(e,t,n){let s=0,a=null;while(s<360){s++;let o=await this.describeStack(e);if(n)try{let c=await this.describeStackEvents(e),l=[];if(a){for(let u of c){if(u.EventId===a)break;l.push(u)}l.reverse()}else if(c.length>0)l=[c[0]];for(let u of l)n(u);if(c.length>0)a=c[0].EventId}catch{}if(o.StackStatus&&t.includes(o.StackStatus))return o;if(o.StackStatus?.includes("FAILED")||o.StackStatus?.includes("ROLLBACK"))throw Error(`Stack reached failed state: ${o.StackStatus}
2473
+ Reason: ${o.StackStatusReason||"Unknown"}`);await new Promise((c)=>setTimeout(c,5000))}throw Error(`Timeout waiting for stack ${e} to complete`)}async waitForStackWithProgress(e,t,n){let i={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[t];if(!i)throw Error(`Unknown waiter: ${t}`);return this.waitForStack(e,i,n)}async createChangeSet(e){let t={StackName:e.stackName,ChangeSetName:e.changeSetName,ChangeSetType:"UPDATE"};if(e.templateBody)t.TemplateBody=e.templateBody;else if(e.templateURL)t.TemplateURL=e.templateURL;if(e.parameters)for(let[r,[i,s]]of Object.entries(e.parameters).entries())t[`Parameters.member.${r+1}.ParameterKey`]=i,t[`Parameters.member.${r+1}.ParameterValue`]=s;if(e.capabilities)for(let[r,i]of e.capabilities.entries())t[`Capabilities.member.${r+1}`]=i;return(await this.request("CreateChangeSet",t)).ChangeSetId}async executeChangeSet(e,t){await this.request("ExecuteChangeSet",{ChangeSetName:e,StackName:t})}async describeStacks(e){let t=typeof e==="string"?e:e.stackName;try{return{Stacks:[await this.describeStack(t)]}}catch{return{Stacks:[]}}}async getStackOutputs(e){let t=await this.request("DescribeStacks",{StackName:e}),r=(t?.DescribeStacksResult||t?.DescribeStacksResponse?.DescribeStacksResult||t)?.Stacks?.member,i=Array.isArray(r)?r[0]:r;if(!i)return{};let s={},a=i.Outputs?.member;if(a){let o=Array.isArray(a)?a:[a];for(let c of o)if(c.OutputKey&&c.OutputValue)s[c.OutputKey]=c.OutputValue}return s}}function tn(e,t=""){let n={};for(let[r,i]of Object.entries(e)){let s=t?`${t}.${r}`:r;if(Array.isArray(i))i.forEach((a,o)=>{if(typeof a==="object")Object.assign(n,tn(a,`${s}.${o+1}`));else n[`${s}.${o+1}`]=String(a)});else if(typeof i==="object"&&i!==null)Object.assign(n,tn(i,s));else if(i!==void 0&&i!==null)n[s]=String(i)}return n}function No(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function t(i,s,a){let o=1,c=a,l=`<${s}`,u=`</${s}>`;while(c<i.length&&o>0){let m=i.indexOf(l,c),p=i.indexOf(u,c);if(p===-1)return-1;if(m!==-1&&m<p){let g=i[m+l.length];if(g===">"||g===" "||g==="/"){let y=i.indexOf(">",m);if(y!==-1&&i[y-1]==="/")c=y+1;else o++,c=y+1}else c=m+l.length}else{if(o--,o===0)return p;c=p+u.length}}return-1}function n(i,s){while(s<i.length&&/\s/.test(i[s]))s++;if(s>=i.length||i[s]!=="<"){let h=i.indexOf("<",s);if(h===-1)return{value:i.slice(s).trim(),end:i.length};return{value:i.slice(s,h).trim(),end:h}}if(i[s+1]==="/")return{value:void 0,end:s};let a=i.slice(s).match(/^<(\w+)([^>]*?)\/?>/);if(!a)return{value:void 0,end:s+1};let o=a[1];if(a[0].endsWith("/>"))return{value:"",end:s+a[0].length};let l=s+a[0].length,u=`</${o}>`,m=t(i,o,l);if(m===-1)return{value:void 0,end:s+a[0].length};let p=i.slice(l,m).trim();if(!p.includes("<"))return{value:p,end:m+u.length};let g={},y=l;while(y<m){while(y<m&&/\s/.test(i[y]))y++;if(y>=m)break;if(i[y]!=="<"||i[y+1]==="/")break;let h=i.slice(y).match(/^<(\w+)/);if(!h)break;let b=h[1],C=n(i,y);if(C.value===void 0){y++;continue}if(b==="member"||g[b]!==void 0){if(!Array.isArray(g[b]))g[b]=g[b]!==void 0?[g[b]]:[];g[b].push(C.value)}else g[b]=C.value;y=C.end}return{value:g,end:m+u.length}}return n(e,0).value||{}}function xo(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function ko(e){let n=(e?.ListStacksResult||e?.ListStacksResponse?.ListStacksResult||e)?.StackSummaries?.member;if(!n)return[];return(Array.isArray(n)?n:[n]).map((i)=>({StackName:i.StackName||"",StackId:i.StackId,StackStatus:i.StackStatus,CreationTime:i.CreationTime,LastUpdatedTime:i.LastUpdatedTime,StackStatusReason:i.StackStatusReason,Description:i.Description}))}function Mo(e){let n=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!n)return[];return(Array.isArray(n)?n:[n]).map((i)=>({StackId:i.StackId||"",EventId:i.EventId||"",StackName:i.StackName||"",LogicalResourceId:i.LogicalResourceId||"",PhysicalResourceId:i.PhysicalResourceId,ResourceType:i.ResourceType||"",Timestamp:i.Timestamp||"",ResourceStatus:i.ResourceStatus||"",ResourceStatusReason:i.ResourceStatusReason}))}await He();var Lo=5242880,nn=5242880;var Oo=5242880;class rn{region;endpoint;forcePathStyle;credentials;credentialOptions;retryOptions;constructor(e={}){this.region=e.region||process.env.AWS_REGION||"us-east-1",this.endpoint=e.endpoint||`https://s3.${this.region}.amazonaws.com`,this.forcePathStyle=e.forcePathStyle||!1,this.credentials=e.credentials,this.credentialOptions=e.credentialOptions,this.retryOptions=e.retryOptions||{}}async getCredentials(){if(this.credentials)return this.credentials;return lt(this.credentialOptions)}buildUrl(e,t){let n=t?encodeURIComponent(t).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return t?`${this.endpoint}/${e}/${n}`:`${this.endpoint}/${e}`;let r=new URL(this.endpoint);return r.hostname=`${e}.${r.hostname}`,t?`${r.origin}/${n}`:r.origin}async get(e,t,n={}){let r=await this.getCredentials(),i=this.buildUrl(e,t),s={};if(n.range)s.Range=n.range;if(n.ifModifiedSince)s["If-Modified-Since"]=n.ifModifiedSince.toUTCString();if(n.ifMatch)s["If-Match"]=n.ifMatch;if(n.ifNoneMatch)s["If-None-Match"]=n.ifNoneMatch;let a=new URL(i);if(n.responseContentType)a.searchParams.set("response-content-type",n.responseContentType);if(n.responseContentDisposition)a.searchParams.set("response-content-disposition",n.responseContentDisposition);let o=H({method:"GET",url:a.toString(),headers:s,...r,service:"s3",region:this.region}),c=await fetch(o.url,{method:o.method,headers:o.headers});if(!c.ok&&c.status!==304){let l=await c.text();throw new z(`Failed to get object: ${l}`,c.status,e,t)}return c}async getText(e,t,n={}){return(await this.get(e,t,n)).text()}async getJSON(e,t,n={}){return(await this.get(e,t,n)).json()}async getBuffer(e,t,n={}){return(await this.get(e,t,n)).arrayBuffer()}async put(e,t,n,r={}){let i,s;if(typeof n==="string")i=new TextEncoder().encode(n).length,s=n;else if(n instanceof ArrayBuffer)i=n.byteLength,s=n;else if(n instanceof Uint8Array)i=n.byteLength,s=n;else if(n instanceof Blob)i=n.size,s=n;else return this.uploadMultipart(e,t,n,{...r,partSize:nn});if(i>Oo){let a=Fo(s).stream();return this.uploadMultipart(e,t,a,{...r,partSize:nn})}return this.putSimple(e,t,s,i,r)}async putSimple(e,t,n,r,i){let s=await this.getCredentials(),a=this.buildUrl(e,t),o={"Content-Length":String(r),"Content-Type":i.contentType||Xr(t)};if(i.contentEncoding)o["Content-Encoding"]=i.contentEncoding;if(i.cacheControl)o["Cache-Control"]=i.cacheControl;if(i.contentDisposition)o["Content-Disposition"]=i.contentDisposition;if(i.storageClass)o["x-amz-storage-class"]=i.storageClass;if(i.serverSideEncryption)o["x-amz-server-side-encryption"]=i.serverSideEncryption;if(i.acl)o["x-amz-acl"]=i.acl;if(i.tagging)o["x-amz-tagging"]=i.tagging;if(i.metadata)for(let[p,g]of Object.entries(i.metadata))o[`x-amz-meta-${p.toLowerCase()}`]=g;let c;if(typeof n==="string")c=n;else if(n instanceof Blob)c=await n.text();else c=new TextDecoder().decode(n instanceof ArrayBuffer?new Uint8Array(n):n);let l=H({method:"PUT",url:a,headers:o,body:c,...s,service:"s3",region:this.region}),u=await fetch(l.url,{method:l.method,headers:l.headers,body:n});if(!u.ok){let p=await u.text();throw new z(`Failed to put object: ${p}`,u.status,e,t)}return{etag:(u.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,t){let n=await this.getCredentials(),r=this.buildUrl(e,t),i=H({method:"DELETE",url:r,...n,service:"s3",region:this.region}),s=await fetch(i.url,{method:i.method,headers:i.headers});if(!s.ok&&s.status!==204){let a=await s.text();throw new z(`Failed to delete object: ${a}`,s.status,e,t)}}async deleteMany(e,t){let n=await this.getCredentials(),r=`${this.buildUrl(e)}?delete`,s=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${t.map((y)=>`<Object><Key>${Bo(y)}</Key></Object>`).join("")}</Delete>`,a=H({method:"POST",url:r,headers:{"Content-Type":"application/xml"},body:s,...n,service:"s3",region:this.region}),o=await fetch(a.url,{method:a.method,headers:a.headers,body:s});if(!o.ok){let y=await o.text();throw new z(`Failed to delete objects: ${y}`,o.status,e)}let c=await o.text(),l=[],u=[],m=/<Deleted><Key>([^<]+)<\/Key>/g,p;while((p=m.exec(c))!==null)l.push(p[1]);let g=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((p=g.exec(c))!==null)u.push({key:p[1],error:`${p[2]}: ${p[3]}`});return{deleted:l,errors:u}}async list(e,t={}){let n=await this.getCredentials(),r=new URL(this.buildUrl(e));if(r.searchParams.set("list-type","2"),t.prefix)r.searchParams.set("prefix",t.prefix);if(t.delimiter)r.searchParams.set("delimiter",t.delimiter);if(t.maxKeys)r.searchParams.set("max-keys",String(t.maxKeys));if(t.continuationToken)r.searchParams.set("continuation-token",t.continuationToken);if(t.startAfter)r.searchParams.set("start-after",t.startAfter);let i=H({method:"GET",url:r.toString(),...n,service:"s3",region:this.region}),s=await fetch(i.url,{method:i.method,headers:i.headers});if(!s.ok){let o=await s.text();throw new z(`Failed to list objects: ${o}`,s.status,e)}let a=await s.text();return $o(a)}async*listAll(e,t={}){let n;do{let r=await this.list(e,{...t,continuationToken:n});for(let i of r.contents)yield i;n=r.nextContinuationToken}while(n)}async head(e,t){let n=await this.getCredentials(),r=this.buildUrl(e,t),i=H({method:"HEAD",url:r,...n,service:"s3",region:this.region}),s=await fetch(i.url,{method:i.method,headers:i.headers});if(s.status===404)return null;if(!s.ok){let o=await s.text();throw new z(`Failed to head object: ${o}`,s.status,e,t)}let a={};return s.headers.forEach((o,c)=>{if(c.toLowerCase().startsWith("x-amz-meta-"))a[c.slice(11)]=o}),{contentLength:Number(s.headers.get("Content-Length")||0),contentType:s.headers.get("Content-Type")||"application/octet-stream",etag:(s.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(s.headers.get("Last-Modified")||0),metadata:a,storageClass:s.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:s.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,t){return await this.head(e,t)!==null}async copy(e,t,n,r,i={}){let s=await this.getCredentials(),a=this.buildUrl(n,r),o={"x-amz-copy-source":`/${e}/${encodeURIComponent(t)}`};if(i.metadataDirective)o["x-amz-metadata-directive"]=i.metadataDirective;if(i.contentType)o["Content-Type"]=i.contentType;if(i.storageClass)o["x-amz-storage-class"]=i.storageClass;if(i.acl)o["x-amz-acl"]=i.acl;if(i.metadata)for(let[g,y]of Object.entries(i.metadata))o[`x-amz-meta-${g.toLowerCase()}`]=y;let c=H({method:"PUT",url:a,headers:o,...s,service:"s3",region:this.region}),l=await fetch(c.url,{method:c.method,headers:c.headers});if(!l.ok){let g=await l.text();throw new z(`Failed to copy object: ${g}`,l.status,n,r)}let m=(await l.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:m?m[1]:""}}async getPresignedUrl(e,t,n={}){let r=await this.getCredentials(),i=this.buildUrl(e,t);return Vr({url:i,method:n.method||"GET",expiresIn:n.expiresIn||3600,...r,service:"s3",region:this.region})}async uploadMultipart(e,t,n,r={}){let i=await this.getCredentials(),s=Math.max(r.partSize||nn,Lo),a,o;if(n instanceof ReadableStream)a=n;else if(n instanceof Blob)a=n.stream(),o=n.size;else{let u=new Blob([n]);a=u.stream(),o=u.size}let{uploadId:c,baseUrl:l}=await this.initiateMultipartUpload(e,t,r);try{let u=await this.uploadParts(e,t,l,c,a,s,i,o,r.concurrency||4,r.onProgress);return await this.completeMultipartUpload(e,t,l,c,u)}catch(u){throw await this.abortMultipartUpload(e,t,c,l).catch(()=>{}),u}}async initiateMultipartUpload(e,t,n){let r=await this.getCredentials(),i=this.buildUrl(e,t),s=`${i}?uploads`,a={"Content-Type":n.contentType||Xr(t)};if(n.storageClass)a["x-amz-storage-class"]=n.storageClass;if(n.serverSideEncryption)a["x-amz-server-side-encryption"]=n.serverSideEncryption;if(n.acl)a["x-amz-acl"]=n.acl;if(n.metadata)for(let[p,g]of Object.entries(n.metadata))a[`x-amz-meta-${p.toLowerCase()}`]=g;let o=H({method:"POST",url:s,headers:a,...r,service:"s3",region:this.region}),c=await fetch(o.url,{method:o.method,headers:o.headers});if(!c.ok){let p=await c.text();throw new z(`Failed to initiate multipart upload: ${p}`,c.status,e,t)}let u=(await c.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!u)throw new z("Failed to parse upload ID from response",0,e,t);let m=i;if(c.url)try{let p=new URL(c.url);p.search="",m=p.toString()}catch{}return{uploadId:u[1],baseUrl:m}}async uploadParts(e,t,n,r,i,s,a,o,c,l){let u=[],m=i.getReader(),p=1,g=new Uint8Array(0),y=0,h=o?Math.ceil(o/s):void 0,b=new Map,C=async(A,R)=>{let P=`${n}?partNumber=${R}&uploadId=${encodeURIComponent(r)}`,E={"Content-Length":String(A.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},w=H({method:"PUT",url:P,headers:E,...a,service:"s3",region:this.region}),I=await fetch(w.url,{method:w.method,headers:w.headers,body:A,redirect:"error"});if(!I.ok){let k=await I.text();throw new z(`Failed to upload part ${R}: ${k}`,I.status,e,t)}let D=(I.headers.get("ETag")||"").replace(/"/g,"");if(!D)throw new z(`Missing ETag for part ${R}`,I.status,e,t);return{partNumber:R,etag:D}},T=async()=>{let A=await Promise.race(b.values());b.delete(A.partNumber),u.push(A)};while(!0){let{done:A,value:R}=await m.read();if(R){let P=new Uint8Array(g.length+R.length);P.set(g),P.set(R,g.length),g=P}while(g.length>=s||A&&g.length>0){let P=g.slice(0,s);g=g.slice(s);let E=p++;if(b.size>=c)await T();if(b.set(E,C(P,E)),y+=P.byteLength,l)l({loaded:y,total:o||y,part:E,totalParts:h||E})}if(A)break}while(b.size>0)await T();return u.sort((A,R)=>A.partNumber-R.partNumber),u}async completeMultipartUpload(e,t,n,r,i){let s=await this.getCredentials(),a=`${n}?uploadId=${encodeURIComponent(r)}`,c=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${i.map((y)=>`<Part><PartNumber>${y.partNumber}</PartNumber><ETag>"${y.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,l=H({method:"POST",url:a,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 y=await u.text();throw new z(`Failed to complete multipart upload: ${y}`,u.status,e,t)}let p=(await u.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:p?p[1]:""}}async abortMultipartUpload(e,t,n,r){let i=await this.getCredentials(),s=`${r??this.buildUrl(e,t)}?uploadId=${encodeURIComponent(n)}`,a=H({method:"DELETE",url:s,...i,service:"s3",region:this.region});await fetch(a.url,{method:a.method,headers:a.headers})}async emptyAndDeleteBucket(e){let n=[];for await(let a of this.listAll(e,{}))if(n.push(a.key),n.length>=1000)await this.deleteMany(e,n),n=[];if(n.length>0)await this.deleteMany(e,n);let r=await this.getCredentials(),i=this.buildUrl(e),s=H({method:"DELETE",url:i,...r,service:"s3",region:this.region});await fetch(s.url,{method:s.method,headers:s.headers})}}class z extends Error{statusCode;bucket;key;constructor(e,t,n,r){super(e);this.statusCode=t;this.bucket=n;this.key=r;this.name="S3Error"}}function $o(e){let t=[],n=[],r=/<Contents>([\s\S]*?)<\/Contents>/g,i;while((i=r.exec(e))!==null){let a=i[1];t.push({key:ie(a,"Key")||"",lastModified:new Date(ie(a,"LastModified")||0),etag:(ie(a,"ETag")||"").replace(/"/g,""),size:Number(ie(a,"Size")||0),storageClass:ie(a,"StorageClass")||"STANDARD"})}let s=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((i=s.exec(e))!==null)n.push(i[1]);return{contents:t,commonPrefixes:n,isTruncated:ie(e,"IsTruncated")==="true",continuationToken:ie(e,"ContinuationToken")||void 0,nextContinuationToken:ie(e,"NextContinuationToken")||void 0,keyCount:Number(ie(e,"KeyCount")||0),maxKeys:Number(ie(e,"MaxKeys")||1000),prefix:ie(e,"Prefix")||void 0,delimiter:ie(e,"Delimiter")||void 0}}function ie(e,t){let n=new RegExp(`<${t}>([^<]*)</${t}>`),r=e.match(n);return r?r[1]:null}function Bo(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function Xr(e){let t=e.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"}[t||""]||"application/octet-stream"}function Fo(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function Go(e){return new rn(e)}await He();class _o{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await je(this.profile)}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async createInvalidation(e){let t=await this.ensureCredentials(),n=e.callerReference||`invalidation-${Date.now()}`,r=`<?xml version="1.0" encoding="UTF-8"?>
2474
2474
  <InvalidationBatch>
2475
2475
  <Paths>
2476
2476
  <Quantity>${e.paths.length}</Quantity>
@@ -2479,23 +2479,23 @@ Reason: ${o.StackStatusReason||"Unknown"}`);await new Promise((c)=>setTimeout(c,
2479
2479
  </Items>
2480
2480
  </Paths>
2481
2481
  <CallerReference>${n}</CallerReference>
2482
- </InvalidationBatch>`,i=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e.distributionId}/invalidation`,s=await De({method:"POST",url:i,service:"cloudfront",region:"us-east-1",headers:{"Content-Type":"text/xml"},body:r,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey,sessionToken:t.sessionToken});return(await wt(s)).Id}async getInvalidation(e,t){let n=await this.ensureCredentials(),r=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e}/invalidation/${t}`,i=await De({method:"GET",url:r,service:"cloudfront",region:"us-east-1",accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,sessionToken:n.sessionToken});return await wt(i)}async listInvalidations(e){let t=await this.ensureCredentials(),n=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e}/invalidation`,r=await De({method:"GET",url:n,service:"cloudfront",region:"us-east-1",accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey,sessionToken:t.sessionToken});return(await wt(r)).Items||[]}async waitForInvalidation(e,t,n=60,r=5000){for(let i=0;i<n;i++){if((await this.getInvalidation(e,t)).Status==="Completed")return;if(i<n-1)await new Promise((a)=>setTimeout(a,r))}throw Error(`Invalidation ${t} did not complete within the expected time`)}async invalidateAll(e){return await this.createInvalidation({distributionId:e,paths:["/*"]})}}class fe extends Error{code;solution;details;constructor(e,t,n,r){super(e);this.code=t;this.solution=n;this.details=r;this.name="CloudError",Error.captureStackTrace?.(this,fe)}toString(){let e=`${this.name} [${this.code}]: ${this.message}`;if(this.solution)e+=`
2482
+ </InvalidationBatch>`,i=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e.distributionId}/invalidation`,s=await Ne({method:"POST",url:i,service:"cloudfront",region:"us-east-1",headers:{"Content-Type":"text/xml"},body:r,accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey,sessionToken:t.sessionToken});return(await It(s)).Id}async getInvalidation(e,t){let n=await this.ensureCredentials(),r=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e}/invalidation/${t}`,i=await Ne({method:"GET",url:r,service:"cloudfront",region:"us-east-1",accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,sessionToken:n.sessionToken});return await It(i)}async listInvalidations(e){let t=await this.ensureCredentials(),n=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e}/invalidation`,r=await Ne({method:"GET",url:n,service:"cloudfront",region:"us-east-1",accessKeyId:t.accessKeyId,secretAccessKey:t.secretAccessKey,sessionToken:t.sessionToken});return(await It(r)).Items||[]}async waitForInvalidation(e,t,n=60,r=5000){for(let i=0;i<n;i++){if((await this.getInvalidation(e,t)).Status==="Completed")return;if(i<n-1)await new Promise((a)=>setTimeout(a,r))}throw Error(`Invalidation ${t} did not complete within the expected time`)}async invalidateAll(e){return await this.createInvalidation({distributionId:e,paths:["/*"]})}}class be extends Error{code;solution;details;constructor(e,t,n,r){super(e);this.code=t;this.solution=n;this.details=r;this.name="CloudError",Error.captureStackTrace?.(this,be)}toString(){let e=`${this.name} [${this.code}]: ${this.message}`;if(this.solution)e+=`
2483
2483
 
2484
2484
  \uD83D\uDCA1 Solution: ${this.solution}`;if(this.details&&Object.keys(this.details).length>0){e+=`
2485
2485
 
2486
2486
  Details:`;for(let[t,n]of Object.entries(this.details))e+=`
2487
- ${t}: ${JSON.stringify(n)}`}return e}}class It extends fe{constructor(e,t,n){super(e,"CONFIG_ERROR",t,n);this.name="ConfigurationError"}}class ve extends fe{constructor(e,t,n){super(e,"CREDENTIAL_ERROR",t,n);this.name="CredentialError"}}class Wo extends fe{constructor(e,t,n){super(e,"DEPLOYMENT_ERROR",t,n);this.name="DeploymentError"}}class ti extends fe{constructor(e,t,n){super(e,"VALIDATION_ERROR",t,n);this.name="ValidationError"}}class Vo extends fe{statusCode;constructor(e,t,n,r){super(e,"AWS_API_ERROR",n,r);this.statusCode=t;this.name="AWSAPIError"}}var Uo={NO_CREDENTIALS:{message:"AWS credentials not found",solution:`Configure AWS credentials using one of these methods:
2487
+ ${t}: ${JSON.stringify(n)}`}return e}}class Dt extends be{constructor(e,t,n){super(e,"CONFIG_ERROR",t,n);this.name="ConfigurationError"}}class Re extends be{constructor(e,t,n){super(e,"CREDENTIAL_ERROR",t,n);this.name="CredentialError"}}class Wo extends be{constructor(e,t,n){super(e,"DEPLOYMENT_ERROR",t,n);this.name="DeploymentError"}}class ti extends be{constructor(e,t,n){super(e,"VALIDATION_ERROR",t,n);this.name="ValidationError"}}class Vo extends be{statusCode;constructor(e,t,n,r){super(e,"AWS_API_ERROR",n,r);this.statusCode=t;this.name="AWSAPIError"}}var Uo={NO_CREDENTIALS:{message:"AWS credentials not found",solution:`Configure AWS credentials using one of these methods:
2488
2488
  1. Set environment variables: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
2489
2489
  2. Create ~/.aws/credentials file with your credentials
2490
2490
  3. Use an IAM role (for EC2 instances)
2491
- 4. Run 'aws configure' if you have AWS CLI installed`},INVALID_CREDENTIALS:{message:"AWS credentials are invalid",solution:"Verify your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are correct. Run: aws sts get-caller-identity"},EXPIRED_CREDENTIALS:{message:"AWS credentials have expired",solution:"Refresh your AWS credentials. If using temporary credentials, generate new ones."},MISSING_CONFIG:{message:"Configuration file not found",solution:"Create a cloud.config.ts file in your project root. Use: cloud init"},INVALID_CONFIG:{message:"Configuration is invalid",solution:"Check your cloud.config.ts file for syntax errors. Use: cloud config:validate"},MISSING_REQUIRED_FIELD:{message:"Required configuration field is missing",solution:"Add the missing field to your cloud.config.ts file"},INVALID_REGION:{message:"AWS region is invalid",solution:"Use a valid AWS region like us-east-1, us-west-2, eu-west-1, etc."},STACK_ALREADY_EXISTS:{message:"CloudFormation stack already exists",solution:"Use: cloud deploy --update to update the existing stack, or cloud destroy to delete it first"},STACK_IN_PROGRESS:{message:"Stack operation already in progress",solution:"Wait for the current operation to complete, or cancel it in the AWS Console"},INSUFFICIENT_PERMISSIONS:{message:"Insufficient IAM permissions",solution:"Ensure your IAM user/role has the necessary permissions for CloudFormation and the resources you're deploying"},RESOURCE_LIMIT_EXCEEDED:{message:"AWS service limit exceeded",solution:"Request a service limit increase in the AWS Console, or clean up unused resources"},ROLLBACK_COMPLETE:{message:"Stack creation failed and rolled back",solution:"Check the CloudFormation events to see which resource failed. Fix the issue and try again."},CIRCULAR_DEPENDENCY:{message:"Circular dependency detected in resources",solution:"Review your resource dependencies and remove the circular reference"},INVALID_RESOURCE_NAME:{message:"Resource name contains invalid characters",solution:"Use only alphanumeric characters and hyphens in resource names"},DUPLICATE_RESOURCE:{message:"Duplicate resource name detected",solution:"Ensure all resource names are unique in your configuration"},VPC_CIDR_CONFLICT:{message:"VPC CIDR block conflicts with existing VPC",solution:"Use a different CIDR block that doesn't overlap with existing VPCs"},SUBNET_CIDR_INVALID:{message:"Subnet CIDR block is invalid or outside VPC range",solution:"Ensure subnet CIDR is within the VPC CIDR range and properly sized"},DB_INSTANCE_LIMIT:{message:"RDS instance limit reached",solution:"Delete unused RDS instances or request a limit increase"},INVALID_DB_NAME:{message:"Database name contains invalid characters",solution:"Use only alphanumeric characters and underscores, starting with a letter"},BUCKET_ALREADY_EXISTS:{message:"S3 bucket name already exists globally",solution:"S3 bucket names must be globally unique. Try a different name with your organization prefix"},INVALID_BUCKET_NAME:{message:"S3 bucket name is invalid",solution:"Use lowercase letters, numbers, and hyphens. Must start/end with letter/number. 3-63 characters."},TEMPLATE_TOO_LARGE:{message:"CloudFormation template exceeds size limit",solution:"Split your infrastructure into multiple stacks or use nested stacks"},INVALID_TEMPLATE:{message:"CloudFormation template is invalid",solution:"Validate your template with: cloud config:validate"},PARAMETER_NOT_FOUND:{message:"CloudFormation parameter not found",solution:"Check that all referenced parameters are defined in your template"}};function Ho(e){return Uo[e]}function ei(e,t){let n=Ho(e);return new fe(n.message,e,n.solution,t)}class z{static verboseMode=!1;static debugMode=!1;static setVerbose(e){this.verboseMode=e}static setDebug(e){this.debugMode=e}static verbose(e,...t){if(this.verboseMode)console.log(`[VERBOSE] ${e}`,...t)}static debug(e,...t){if(this.debugMode)console.log(`[DEBUG] ${e}`,...t)}static info(e,...t){console.log(`ℹ ${e}`,...t)}static warn(e,...t){console.warn(`⚠ ${e}`,...t)}static error(e,t){if(console.error(`✖ ${e}`),t){if(t instanceof fe)console.error(t.toString());else console.error(t.message);if(this.debugMode&&t.stack)console.error(`
2492
- Stack trace:`),console.error(t.stack)}}static success(e){console.log(`✔ ${e}`)}}function by(e){if(!e)throw ei("MISSING_CONFIG");if(!e.project)throw new It("Missing required field: project","Add a project configuration with name, slug, and region",{field:"project"});if(!e.project.name)throw new It("Missing required field: project.name","Add a project name to your configuration",{field:"project.name"});if(!e.project.slug)throw new It("Missing required field: project.slug","Add a project slug (lowercase, alphanumeric with hyphens)",{field:"project.slug"});if(!/^[a-z0-9-]+$/.test(e.project.slug))throw new ti("Invalid project slug format","Use only lowercase letters, numbers, and hyphens",{slug:e.project.slug});if(e.project.region){if(!["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"].includes(e.project.region))throw ei("INVALID_REGION",{region:e.project.region})}z.success("Configuration validation passed")}function Sy(e){let t=[];if(e.environments?.production&&e.infrastructure?.database){let n=e.infrastructure.database;if((n.postgres||n.mysql)&&!n.postgres?.multiAZ&&!n.mysql?.multiAZ)t.push("Production database should use Multi-AZ for high availability")}if(e.infrastructure?.storage){for(let[n,r]of Object.entries(e.infrastructure.storage))if(r.encryption===!1)t.push(`Storage "${n}" is not encrypted - consider enabling encryption for security`)}if(e.infrastructure?.storage){for(let[n,r]of Object.entries(e.infrastructure.storage))if(r.public===!0)t.push(`Storage "${n}" is publicly accessible - ensure this is intentional`)}if(e.infrastructure?.database){let n=e.infrastructure.database;if(n.postgres||n.mysql){let r=n.postgres?.backupRetentionDays||n.mysql?.backupRetentionDays;if(!r||r<7)t.push("Database backup retention is less than 7 days - consider increasing for production")}}if(!e.infrastructure?.monitoring)t.push("No monitoring configured - consider adding CloudWatch alarms");return t}async function Ty(e="default"){try{z.verbose("Resolving AWS credentials...");let t=await Ue(e);if(!t.accessKeyId||!t.secretAccessKey)throw new ve("AWS credentials are incomplete","Ensure both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are set");z.verbose("Credentials resolved successfully"),z.debug("Access Key ID:",t.accessKeyId.substring(0,8)+"..."),z.verbose("Testing credentials with GetCallerIdentity...");let n;try{n=await Zr(t),z.verbose("Credentials are valid"),z.debug("Account ID:",n)}catch(r){if(r instanceof Error)if(r.message.includes("InvalidClientTokenId"))throw new ve("Invalid AWS access key ID","Check that your AWS_ACCESS_KEY_ID is correct");else if(r.message.includes("SignatureDoesNotMatch"))throw new ve("Invalid AWS secret access key","Check that your AWS_SECRET_ACCESS_KEY is correct");else if(r.message.includes("ExpiredToken"))throw new ve("AWS credentials have expired","Refresh your temporary credentials or use long-term credentials");else throw new ve(`Failed to validate credentials: ${r.message}`,"Verify your AWS credentials are correct and have the necessary permissions");throw r}return{valid:!0,accountId:n,region:t.region}}catch(t){if(t instanceof ve)throw t;return{valid:!1,error:t instanceof Error?t.message:"Unknown error"}}}async function Ry(e,t){return{allowed:t,denied:[]}}function jo(e){let t=new Set(["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate","cloudformation:ListStacks"]);if(e.infrastructure){if(e.infrastructure.storage)t.add("s3:CreateBucket"),t.add("s3:DeleteBucket"),t.add("s3:PutBucketPolicy"),t.add("s3:PutBucketVersioning"),t.add("s3:PutBucketEncryption"),t.add("s3:PutObject"),t.add("s3:GetObject");if(e.infrastructure.compute){if(e.infrastructure.compute.server)t.add("ec2:RunInstances"),t.add("ec2:TerminateInstances"),t.add("ec2:DescribeInstances"),t.add("autoscaling:CreateAutoScalingGroup"),t.add("autoscaling:UpdateAutoScalingGroup"),t.add("autoscaling:DeleteAutoScalingGroup"),t.add("elasticloadbalancing:CreateLoadBalancer"),t.add("elasticloadbalancing:DeleteLoadBalancer");if(e.infrastructure.compute.fargate)t.add("ecs:CreateCluster"),t.add("ecs:DeleteCluster"),t.add("ecs:CreateService"),t.add("ecs:UpdateService"),t.add("ecs:DeleteService"),t.add("ecs:RegisterTaskDefinition")}if(e.infrastructure.database){if(e.infrastructure.database.postgres||e.infrastructure.database.mysql)t.add("rds:CreateDBInstance"),t.add("rds:DeleteDBInstance"),t.add("rds:ModifyDBInstance"),t.add("rds:DescribeDBInstances");if(e.infrastructure.database.dynamodb)t.add("dynamodb:CreateTable"),t.add("dynamodb:DeleteTable"),t.add("dynamodb:UpdateTable"),t.add("dynamodb:DescribeTable")}if(e.infrastructure.functions)t.add("lambda:CreateFunction"),t.add("lambda:DeleteFunction"),t.add("lambda:UpdateFunctionCode"),t.add("lambda:UpdateFunctionConfiguration"),t.add("lambda:AddPermission");if(e.infrastructure.cdn)t.add("cloudfront:CreateDistribution"),t.add("cloudfront:UpdateDistribution"),t.add("cloudfront:DeleteDistribution"),t.add("cloudfront:GetDistribution");if(e.infrastructure.network)t.add("ec2:CreateVpc"),t.add("ec2:DeleteVpc"),t.add("ec2:CreateSubnet"),t.add("ec2:DeleteSubnet"),t.add("ec2:CreateInternetGateway"),t.add("ec2:DeleteInternetGateway"),t.add("ec2:CreateNatGateway"),t.add("ec2:DeleteNatGateway"),t.add("ec2:CreateRouteTable"),t.add("ec2:DeleteRouteTable"),t.add("ec2:CreateSecurityGroup"),t.add("ec2:DeleteSecurityGroup")}return t.add("iam:CreateRole"),t.add("iam:DeleteRole"),t.add("iam:AttachRolePolicy"),t.add("iam:DetachRolePolicy"),t.add("iam:PutRolePolicy"),t.add("iam:GetRole"),t.add("iam:PassRole"),Array.from(t).sort()}function Py(e){let t=jo(e);return JSON.stringify({Version:"2012-10-17",Statement:[{Effect:"Allow",Action:t,Resource:"*"}]},null,2)}var ee={ec2:{"Running On-Demand Instances":20,"Elastic IPs":5,VPCs:5,"Internet Gateways":5,"NAT Gateways":5,"Security Groups":500},rds:{"DB Instances":40,"DB Snapshots":100,"DB Parameter Groups":50},lambda:{"Concurrent Executions":1000,"Function Storage":80530636800},s3:{Buckets:100},cloudformation:{Stacks:200,StackSets:100},elasticache:{Nodes:100,Clusters:100},dynamodb:{Tables:256},ecs:{Clusters:1e4,"Services per Cluster":2000}};async function Iy(e){let t=[];if(z.verbose("Checking AWS service quotas..."),e.infrastructure?.compute?.server){let r=e.infrastructure.compute.server.autoScaling?.max||1;t.push({service:"EC2",quotaName:"Running On-Demand Instances",currentValue:r,limit:ee.ec2["Running On-Demand Instances"],percentage:r/ee.ec2["Running On-Demand Instances"]*100,warning:r>ee.ec2["Running On-Demand Instances"]*0.8})}if(e.infrastructure?.network?.vpc)t.push({service:"EC2",quotaName:"VPCs",currentValue:1,limit:ee.ec2.VPCs,percentage:1/ee.ec2.VPCs*100,warning:!1});if(e.infrastructure?.database?.postgres||e.infrastructure?.database?.mysql)t.push({service:"RDS",quotaName:"DB Instances",currentValue:1,limit:ee.rds["DB Instances"],percentage:1/ee.rds["DB Instances"]*100,warning:!1});if(e.infrastructure?.storage){let r=Object.keys(e.infrastructure.storage).length;t.push({service:"S3",quotaName:"Buckets",currentValue:r,limit:ee.s3.Buckets,percentage:r/ee.s3.Buckets*100,warning:r>ee.s3.Buckets*0.8})}if(e.infrastructure?.functions){let r=0;for(let i of Object.values(e.infrastructure.functions))if(Array.isArray(i))r+=i.length;t.push({service:"Lambda",quotaName:"Functions (estimated)",currentValue:r,limit:1000,percentage:r/1000*100,warning:r>800})}if(e.infrastructure?.database?.dynamodb){let r=e.infrastructure.database.dynamodb.tables?.length||0;t.push({service:"DynamoDB",quotaName:"Tables",currentValue:r,limit:ee.dynamodb.Tables,percentage:r/ee.dynamodb.Tables*100,warning:r>ee.dynamodb.Tables*0.8})}let n=t.filter((r)=>r.warning);if(n.length>0){z.warn("Service quota warnings detected:");for(let r of n)z.warn(` ${r.service} - ${r.quotaName}: ${r.currentValue}/${r.limit} (${r.percentage.toFixed(1)}%)`)}else z.verbose("All service quotas are within limits");return t}function Dy(e){if(e.length===0)return"No quotas to check";let t=`Service Quota Usage:
2491
+ 4. Run 'aws configure' if you have AWS CLI installed`},INVALID_CREDENTIALS:{message:"AWS credentials are invalid",solution:"Verify your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are correct. Run: aws sts get-caller-identity"},EXPIRED_CREDENTIALS:{message:"AWS credentials have expired",solution:"Refresh your AWS credentials. If using temporary credentials, generate new ones."},MISSING_CONFIG:{message:"Configuration file not found",solution:"Create a cloud.config.ts file in your project root. Use: cloud init"},INVALID_CONFIG:{message:"Configuration is invalid",solution:"Check your cloud.config.ts file for syntax errors. Use: cloud config:validate"},MISSING_REQUIRED_FIELD:{message:"Required configuration field is missing",solution:"Add the missing field to your cloud.config.ts file"},INVALID_REGION:{message:"AWS region is invalid",solution:"Use a valid AWS region like us-east-1, us-west-2, eu-west-1, etc."},STACK_ALREADY_EXISTS:{message:"CloudFormation stack already exists",solution:"Use: cloud deploy --update to update the existing stack, or cloud destroy to delete it first"},STACK_IN_PROGRESS:{message:"Stack operation already in progress",solution:"Wait for the current operation to complete, or cancel it in the AWS Console"},INSUFFICIENT_PERMISSIONS:{message:"Insufficient IAM permissions",solution:"Ensure your IAM user/role has the necessary permissions for CloudFormation and the resources you're deploying"},RESOURCE_LIMIT_EXCEEDED:{message:"AWS service limit exceeded",solution:"Request a service limit increase in the AWS Console, or clean up unused resources"},ROLLBACK_COMPLETE:{message:"Stack creation failed and rolled back",solution:"Check the CloudFormation events to see which resource failed. Fix the issue and try again."},CIRCULAR_DEPENDENCY:{message:"Circular dependency detected in resources",solution:"Review your resource dependencies and remove the circular reference"},INVALID_RESOURCE_NAME:{message:"Resource name contains invalid characters",solution:"Use only alphanumeric characters and hyphens in resource names"},DUPLICATE_RESOURCE:{message:"Duplicate resource name detected",solution:"Ensure all resource names are unique in your configuration"},VPC_CIDR_CONFLICT:{message:"VPC CIDR block conflicts with existing VPC",solution:"Use a different CIDR block that doesn't overlap with existing VPCs"},SUBNET_CIDR_INVALID:{message:"Subnet CIDR block is invalid or outside VPC range",solution:"Ensure subnet CIDR is within the VPC CIDR range and properly sized"},DB_INSTANCE_LIMIT:{message:"RDS instance limit reached",solution:"Delete unused RDS instances or request a limit increase"},INVALID_DB_NAME:{message:"Database name contains invalid characters",solution:"Use only alphanumeric characters and underscores, starting with a letter"},BUCKET_ALREADY_EXISTS:{message:"S3 bucket name already exists globally",solution:"S3 bucket names must be globally unique. Try a different name with your organization prefix"},INVALID_BUCKET_NAME:{message:"S3 bucket name is invalid",solution:"Use lowercase letters, numbers, and hyphens. Must start/end with letter/number. 3-63 characters."},TEMPLATE_TOO_LARGE:{message:"CloudFormation template exceeds size limit",solution:"Split your infrastructure into multiple stacks or use nested stacks"},INVALID_TEMPLATE:{message:"CloudFormation template is invalid",solution:"Validate your template with: cloud config:validate"},PARAMETER_NOT_FOUND:{message:"CloudFormation parameter not found",solution:"Check that all referenced parameters are defined in your template"}};function Ho(e){return Uo[e]}function ei(e,t){let n=Ho(e);return new be(n.message,e,n.solution,t)}class Q{static verboseMode=!1;static debugMode=!1;static setVerbose(e){this.verboseMode=e}static setDebug(e){this.debugMode=e}static verbose(e,...t){if(this.verboseMode)console.log(`[VERBOSE] ${e}`,...t)}static debug(e,...t){if(this.debugMode)console.log(`[DEBUG] ${e}`,...t)}static info(e,...t){console.log(`ℹ ${e}`,...t)}static warn(e,...t){console.warn(`⚠ ${e}`,...t)}static error(e,t){if(console.error(`✖ ${e}`),t){if(t instanceof be)console.error(t.toString());else console.error(t.message);if(this.debugMode&&t.stack)console.error(`
2492
+ Stack trace:`),console.error(t.stack)}}static success(e){console.log(`✔ ${e}`)}}function by(e){if(!e)throw ei("MISSING_CONFIG");if(!e.project)throw new Dt("Missing required field: project","Add a project configuration with name, slug, and region",{field:"project"});if(!e.project.name)throw new Dt("Missing required field: project.name","Add a project name to your configuration",{field:"project.name"});if(!e.project.slug)throw new Dt("Missing required field: project.slug","Add a project slug (lowercase, alphanumeric with hyphens)",{field:"project.slug"});if(!/^[a-z0-9-]+$/.test(e.project.slug))throw new ti("Invalid project slug format","Use only lowercase letters, numbers, and hyphens",{slug:e.project.slug});if(e.project.region){if(!["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"].includes(e.project.region))throw ei("INVALID_REGION",{region:e.project.region})}Q.success("Configuration validation passed")}function Sy(e){let t=[];if(e.environments?.production&&e.infrastructure?.database){let n=e.infrastructure.database;if((n.postgres||n.mysql)&&!n.postgres?.multiAZ&&!n.mysql?.multiAZ)t.push("Production database should use Multi-AZ for high availability")}if(e.infrastructure?.storage){for(let[n,r]of Object.entries(e.infrastructure.storage))if(r.encryption===!1)t.push(`Storage "${n}" is not encrypted - consider enabling encryption for security`)}if(e.infrastructure?.storage){for(let[n,r]of Object.entries(e.infrastructure.storage))if(r.public===!0)t.push(`Storage "${n}" is publicly accessible - ensure this is intentional`)}if(e.infrastructure?.database){let n=e.infrastructure.database;if(n.postgres||n.mysql){let r=n.postgres?.backupRetentionDays||n.mysql?.backupRetentionDays;if(!r||r<7)t.push("Database backup retention is less than 7 days - consider increasing for production")}}if(!e.infrastructure?.monitoring)t.push("No monitoring configured - consider adding CloudWatch alarms");return t}async function Ty(e="default"){try{Q.verbose("Resolving AWS credentials...");let t=await je(e);if(!t.accessKeyId||!t.secretAccessKey)throw new Re("AWS credentials are incomplete","Ensure both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are set");Q.verbose("Credentials resolved successfully"),Q.debug("Access Key ID:",t.accessKeyId.substring(0,8)+"..."),Q.verbose("Testing credentials with GetCallerIdentity...");let n;try{n=await Zr(t),Q.verbose("Credentials are valid"),Q.debug("Account ID:",n)}catch(r){if(r instanceof Error)if(r.message.includes("InvalidClientTokenId"))throw new Re("Invalid AWS access key ID","Check that your AWS_ACCESS_KEY_ID is correct");else if(r.message.includes("SignatureDoesNotMatch"))throw new Re("Invalid AWS secret access key","Check that your AWS_SECRET_ACCESS_KEY is correct");else if(r.message.includes("ExpiredToken"))throw new Re("AWS credentials have expired","Refresh your temporary credentials or use long-term credentials");else throw new Re(`Failed to validate credentials: ${r.message}`,"Verify your AWS credentials are correct and have the necessary permissions");throw r}return{valid:!0,accountId:n,region:t.region}}catch(t){if(t instanceof Re)throw t;return{valid:!1,error:t instanceof Error?t.message:"Unknown error"}}}async function Ry(e,t){return{allowed:t,denied:[]}}function jo(e){let t=new Set(["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate","cloudformation:ListStacks"]);if(e.infrastructure){if(e.infrastructure.storage)t.add("s3:CreateBucket"),t.add("s3:DeleteBucket"),t.add("s3:PutBucketPolicy"),t.add("s3:PutBucketVersioning"),t.add("s3:PutBucketEncryption"),t.add("s3:PutObject"),t.add("s3:GetObject");if(e.infrastructure.compute){if(e.infrastructure.compute.server)t.add("ec2:RunInstances"),t.add("ec2:TerminateInstances"),t.add("ec2:DescribeInstances"),t.add("autoscaling:CreateAutoScalingGroup"),t.add("autoscaling:UpdateAutoScalingGroup"),t.add("autoscaling:DeleteAutoScalingGroup"),t.add("elasticloadbalancing:CreateLoadBalancer"),t.add("elasticloadbalancing:DeleteLoadBalancer");if(e.infrastructure.compute.fargate)t.add("ecs:CreateCluster"),t.add("ecs:DeleteCluster"),t.add("ecs:CreateService"),t.add("ecs:UpdateService"),t.add("ecs:DeleteService"),t.add("ecs:RegisterTaskDefinition")}if(e.infrastructure.database){if(e.infrastructure.database.postgres||e.infrastructure.database.mysql)t.add("rds:CreateDBInstance"),t.add("rds:DeleteDBInstance"),t.add("rds:ModifyDBInstance"),t.add("rds:DescribeDBInstances");if(e.infrastructure.database.dynamodb)t.add("dynamodb:CreateTable"),t.add("dynamodb:DeleteTable"),t.add("dynamodb:UpdateTable"),t.add("dynamodb:DescribeTable")}if(e.infrastructure.functions)t.add("lambda:CreateFunction"),t.add("lambda:DeleteFunction"),t.add("lambda:UpdateFunctionCode"),t.add("lambda:UpdateFunctionConfiguration"),t.add("lambda:AddPermission");if(e.infrastructure.cdn)t.add("cloudfront:CreateDistribution"),t.add("cloudfront:UpdateDistribution"),t.add("cloudfront:DeleteDistribution"),t.add("cloudfront:GetDistribution");if(e.infrastructure.network)t.add("ec2:CreateVpc"),t.add("ec2:DeleteVpc"),t.add("ec2:CreateSubnet"),t.add("ec2:DeleteSubnet"),t.add("ec2:CreateInternetGateway"),t.add("ec2:DeleteInternetGateway"),t.add("ec2:CreateNatGateway"),t.add("ec2:DeleteNatGateway"),t.add("ec2:CreateRouteTable"),t.add("ec2:DeleteRouteTable"),t.add("ec2:CreateSecurityGroup"),t.add("ec2:DeleteSecurityGroup")}return t.add("iam:CreateRole"),t.add("iam:DeleteRole"),t.add("iam:AttachRolePolicy"),t.add("iam:DetachRolePolicy"),t.add("iam:PutRolePolicy"),t.add("iam:GetRole"),t.add("iam:PassRole"),Array.from(t).sort()}function Py(e){let t=jo(e);return JSON.stringify({Version:"2012-10-17",Statement:[{Effect:"Allow",Action:t,Resource:"*"}]},null,2)}var te={ec2:{"Running On-Demand Instances":20,"Elastic IPs":5,VPCs:5,"Internet Gateways":5,"NAT Gateways":5,"Security Groups":500},rds:{"DB Instances":40,"DB Snapshots":100,"DB Parameter Groups":50},lambda:{"Concurrent Executions":1000,"Function Storage":80530636800},s3:{Buckets:100},cloudformation:{Stacks:200,StackSets:100},elasticache:{Nodes:100,Clusters:100},dynamodb:{Tables:256},ecs:{Clusters:1e4,"Services per Cluster":2000}};async function Iy(e){let t=[];if(Q.verbose("Checking AWS service quotas..."),e.infrastructure?.compute?.server){let r=e.infrastructure.compute.server.autoScaling?.max||1;t.push({service:"EC2",quotaName:"Running On-Demand Instances",currentValue:r,limit:te.ec2["Running On-Demand Instances"],percentage:r/te.ec2["Running On-Demand Instances"]*100,warning:r>te.ec2["Running On-Demand Instances"]*0.8})}if(e.infrastructure?.network?.vpc)t.push({service:"EC2",quotaName:"VPCs",currentValue:1,limit:te.ec2.VPCs,percentage:1/te.ec2.VPCs*100,warning:!1});if(e.infrastructure?.database?.postgres||e.infrastructure?.database?.mysql)t.push({service:"RDS",quotaName:"DB Instances",currentValue:1,limit:te.rds["DB Instances"],percentage:1/te.rds["DB Instances"]*100,warning:!1});if(e.infrastructure?.storage){let r=Object.keys(e.infrastructure.storage).length;t.push({service:"S3",quotaName:"Buckets",currentValue:r,limit:te.s3.Buckets,percentage:r/te.s3.Buckets*100,warning:r>te.s3.Buckets*0.8})}if(e.infrastructure?.functions){let r=0;for(let i of Object.values(e.infrastructure.functions))if(Array.isArray(i))r+=i.length;t.push({service:"Lambda",quotaName:"Functions (estimated)",currentValue:r,limit:1000,percentage:r/1000*100,warning:r>800})}if(e.infrastructure?.database?.dynamodb){let r=e.infrastructure.database.dynamodb.tables?.length||0;t.push({service:"DynamoDB",quotaName:"Tables",currentValue:r,limit:te.dynamodb.Tables,percentage:r/te.dynamodb.Tables*100,warning:r>te.dynamodb.Tables*0.8})}let n=t.filter((r)=>r.warning);if(n.length>0){Q.warn("Service quota warnings detected:");for(let r of n)Q.warn(` ${r.service} - ${r.quotaName}: ${r.currentValue}/${r.limit} (${r.percentage.toFixed(1)}%)`)}else Q.verbose("All service quotas are within limits");return t}function Dy(e){if(e.length===0)return"No quotas to check";let t=`Service Quota Usage:
2493
2493
 
2494
2494
  `,n=e.reduce((r,i)=>{if(!r[i.service])r[i.service]=[];return r[i.service].push(i),r},{});for(let[r,i]of Object.entries(n)){t+=`${r}:
2495
2495
  `;for(let s of i){let a=s.warning?"⚠":"✓";t+=` ${a} ${s.quotaName}: ${s.currentValue}/${s.limit} (${s.percentage.toFixed(1)}%)
2496
2496
  `}t+=`
2497
- `}return t}function Ny(e){let t=[];for(let n of e)if(n.percentage>=100)t.push(`Request quota increase for ${n.service} - ${n.quotaName} (currently ${n.limit})`);else if(n.warning)t.push(`Consider requesting quota increase for ${n.service} - ${n.quotaName} (${n.percentage.toFixed(1)}% used)`);return t}import{createHash as ii}from"node:crypto";import{existsSync as Dt,mkdirSync as Ko,readdirSync as ni,readFileSync as ri,unlinkSync as lt,writeFileSync as qo}from"node:fs";import{join as sn}from"node:path";class on{cacheDir;ttl;constructor(e,t={}){this.cacheDir=e,this.ttl=t.ttl||86400000}ensureCacheDir(){if(!Dt(this.cacheDir))Ko(this.cacheDir,{recursive:!0})}getCachePath(e){let t=ii("sha256").update(e).digest("hex");return sn(this.cacheDir,`${t}.json`)}get(e){let t=this.getCachePath(e);if(!Dt(t))return;try{let n=ri(t,"utf-8"),r=JSON.parse(n);if(Date.now()-r.timestamp>this.ttl){lt(t);return}return r.value}catch{lt(t);return}}set(e,t,n){this.ensureCacheDir();let r=this.getCachePath(e),i={value:t,timestamp:Date.now(),hash:n};qo(r,JSON.stringify(i),"utf-8")}has(e){return this.get(e)!==void 0}clear(){if(!Dt(this.cacheDir))return;let e=ni(this.cacheDir);for(let t of e)lt(sn(this.cacheDir,t))}prune(){if(!Dt(this.cacheDir))return;let e=ni(this.cacheDir),t=Date.now();for(let n of e){let r=sn(this.cacheDir,n);try{let i=ri(r,"utf-8"),s=JSON.parse(i);if(t-s.timestamp>this.ttl)lt(r)}catch{lt(r)}}}}class cn{cache;constructor(e=Jn("cache","templates")){this.cache=new on(e,{ttl:86400000})}getTemplate(e){return this.cache.get(`template:${e}`)}setTemplate(e,t){let n=this.hashTemplate(t);this.cache.set(`template:${e}`,t,n)}hasChanged(e,t){let n=this.cache.get(`template:${e}`);if(!n)return!0;let r=this.hashTemplate(n),i=this.hashTemplate(t);return r!==i}hashTemplate(e){return ii("sha256").update(e).digest("hex")}clear(){this.cache.clear()}prune(){this.cache.prune()}}var an=null;function zo(){if(!an)an=new cn;return an}import{createHash as ln}from"node:crypto";import{createReadStream as Qo,readdirSync as Jo,statSync as Nt}from"node:fs";import{join as Yo,relative as Zo}from"node:path";async function si(e,t={}){let n=t.algorithm||"sha256",r=t.chunkSize||65536;return new Promise((i,s)=>{let a=ln(n),o=Qo(e,{highWaterMark:r});o.on("data",(c)=>a.update(c)),o.on("end",()=>i(a.digest("hex"))),o.on("error",s)})}function ai(e,t="sha256"){return ln(t).update(e).digest("hex")}function Wy(e,t="sha256"){return ln(t).update(e).digest("hex")}async function Vy(e,t={}){let n=t.ignorePatterns||["node_modules",".git","dist","build",$e()],r=[];async function i(s){let a=Jo(s,{withFileTypes:!0});for(let o of a){let c=Yo(s,o.name),l=Zo(e,c);if(n.some((u)=>l.includes(u)))continue;if(o.isDirectory())await i(c);else if(o.isFile()){let u=Nt(c),m=await si(c,t);r.push({path:l,hash:m,size:u.size,mtime:u.mtimeMs})}}}return await i(e),r}function Uy(e){let n=[...e].sort((r,i)=>r.path.localeCompare(i.path)).map((r)=>`${r.path}:${r.hash}`).join(`
2498
- `);return ai(n)}function Hy(e){let t=Nt(e);return ai(`${e}:${t.size}:${t.mtimeMs}`)}function jy(e,t){let n=new Map(e.map((o)=>[o.path,o])),r=new Map(t.map((o)=>[o.path,o])),i=[],s=[],a=[];for(let[o,c]of r){let l=n.get(o);if(!l)i.push(c);else if(l.hash!==c.hash)s.push(c)}for(let[o,c]of n)if(!r.has(o))a.push(c);return{added:i,modified:s,deleted:a}}class Xo{cache;constructor(){this.cache=new Map}get(e){let t=Nt(e),n=this.cache.get(e);if(n&&n.mtime===t.mtimeMs&&n.size===t.size)return n.hash;return}set(e,t){let n=Nt(e);this.cache.set(e,{hash:t,mtime:n.mtimeMs,size:n.size})}async getOrCompute(e,t={}){let n=this.get(e);if(n)return n;let r=await si(e,t);return this.set(e,r),r}clear(){this.cache.clear()}}async function un(e,t={}){let n=t.concurrency||5,r=t.stopOnError??!0,i=[],s=[],a=Date.now(),o=[...e],c=[];async function l(p,g){try{let y=await p();i[g]=y}catch(y){let h=y instanceof Error?y:Error(String(y));if(s.push(h),r)throw o.length=0,h}}let u=0;while(o.length>0||c.length>0){while(c.length<n&&o.length>0){let p=o.shift(),g=u++,y=l(p,g);c.push(y)}if(c.length>0){await Promise.race(c);for(let p=c.length-1;p>=0;p--)if(await Promise.race([c[p].then(()=>!0),Promise.resolve(!1)]))c.splice(p,1)}if(r&&s.length>0)break}let m=Date.now()-a;return{results:i.filter((p)=>p!==void 0),errors:s,duration:m}}async function qy(e,t,n={}){let r=e.map((i)=>()=>t(i));return un(r,n)}async function zy(e,t,n=5){let r=e.map((s,a)=>()=>t(s,a)),i=await un(r,{concurrency:n,stopOnError:!1});if(i.errors.length>0)throw AggregateError(i.errors,"Parallel map failed");return i.results}async function Qy(e,t={}){let n=t.retries||3,r=t.retryDelay||1000,i=e.map((s)=>async()=>{let a;for(let o=0;o<=n;o++)try{return await s()}catch(c){if(a=c instanceof Error?c:Error(String(c)),o<n)await oi(r*(o+1))}throw a});return un(i,t)}async function Jy(e){let t=[];for(let n of e){let r=await n();t.push(r)}return t}function oi(e){return new Promise((t)=>setTimeout(t,e))}async function Yy(e,t,n="Operation timed out"){return Promise.race([e(),new Promise((r,i)=>setTimeout(()=>i(Error(n)),t))])}class ec{maxConcurrent;minInterval;queue=[];running=0;lastExecution=0;constructor(e=5,t=100){this.maxConcurrent=e;this.minInterval=t}async execute(e){await this.waitForSlot(),this.running++,this.lastExecution=Date.now();try{return await e()}finally{this.running--,this.processQueue()}}waitForSlot(){if(this.running<this.maxConcurrent){let e=Date.now()-this.lastExecution;if(e>=this.minInterval)return Promise.resolve();return oi(this.minInterval-e)}return new Promise((e)=>this.queue.push(e))}processQueue(){if(this.queue.length>0&&this.running<this.maxConcurrent)this.queue.shift()()}stats(){return{running:this.running,queued:this.queue.length}}}function tc(e,t){let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}async function Zy(e,t,n){let r=tc(e,t),i=[];for(let s of r){let a=await n(s);i.push(...a)}return i}function ef(e,t){let n=[],r=[],i=[],s=[],a=e.Resources||{},o=t.Resources||{},c=new Set(Object.keys(a)),l=new Set(Object.keys(o));for(let p of l)if(!c.has(p))n.push(p);for(let p of c)if(!l.has(p))i.push(p);for(let p of l)if(c.has(p)){let g=a[p],y=o[p];if(JSON.stringify(g)!==JSON.stringify(y))r.push(p);else s.push(p)}let u=JSON.stringify(e.Parameters||{})!==JSON.stringify(t.Parameters||{}),m=JSON.stringify(e.Outputs||{})!==JSON.stringify(t.Outputs||{});return{added:n,modified:r,deleted:i,unchanged:s,parametersChanged:u,outputsChanged:m,hasChanges:n.length>0||r.length>0||i.length>0||u||m}}function tf(e){let t=[];if(!e.hasChanges)return"No changes detected";if(e.added.length>0){t.push(`Added resources (${e.added.length}):`);for(let n of e.added)t.push(` + ${n}`)}if(e.modified.length>0){t.push(`Modified resources (${e.modified.length}):`);for(let n of e.modified)t.push(` ~ ${n}`)}if(e.deleted.length>0){t.push(`Deleted resources (${e.deleted.length}):`);for(let n of e.deleted)t.push(` - ${n}`)}if(e.parametersChanged)t.push("Parameters changed");if(e.outputsChanged)t.push("Outputs changed");return t.join(`
2497
+ `}return t}function Ny(e){let t=[];for(let n of e)if(n.percentage>=100)t.push(`Request quota increase for ${n.service} - ${n.quotaName} (currently ${n.limit})`);else if(n.warning)t.push(`Consider requesting quota increase for ${n.service} - ${n.quotaName} (${n.percentage.toFixed(1)}% used)`);return t}import{createHash as ii}from"node:crypto";import{existsSync as Nt,mkdirSync as Ko,readdirSync as ni,readFileSync as ri,unlinkSync as ut,writeFileSync as qo}from"node:fs";import{join as sn}from"node:path";class on{cacheDir;ttl;constructor(e,t={}){this.cacheDir=e,this.ttl=t.ttl||86400000}ensureCacheDir(){if(!Nt(this.cacheDir))Ko(this.cacheDir,{recursive:!0})}getCachePath(e){let t=ii("sha256").update(e).digest("hex");return sn(this.cacheDir,`${t}.json`)}get(e){let t=this.getCachePath(e);if(!Nt(t))return;try{let n=ri(t,"utf-8"),r=JSON.parse(n);if(Date.now()-r.timestamp>this.ttl){ut(t);return}return r.value}catch{ut(t);return}}set(e,t,n){this.ensureCacheDir();let r=this.getCachePath(e),i={value:t,timestamp:Date.now(),hash:n};qo(r,JSON.stringify(i),"utf-8")}has(e){return this.get(e)!==void 0}clear(){if(!Nt(this.cacheDir))return;let e=ni(this.cacheDir);for(let t of e)ut(sn(this.cacheDir,t))}prune(){if(!Nt(this.cacheDir))return;let e=ni(this.cacheDir),t=Date.now();for(let n of e){let r=sn(this.cacheDir,n);try{let i=ri(r,"utf-8"),s=JSON.parse(i);if(t-s.timestamp>this.ttl)ut(r)}catch{ut(r)}}}}class cn{cache;constructor(e=Jn("cache","templates")){this.cache=new on(e,{ttl:86400000})}getTemplate(e){return this.cache.get(`template:${e}`)}setTemplate(e,t){let n=this.hashTemplate(t);this.cache.set(`template:${e}`,t,n)}hasChanged(e,t){let n=this.cache.get(`template:${e}`);if(!n)return!0;let r=this.hashTemplate(n),i=this.hashTemplate(t);return r!==i}hashTemplate(e){return ii("sha256").update(e).digest("hex")}clear(){this.cache.clear()}prune(){this.cache.prune()}}var an=null;function zo(){if(!an)an=new cn;return an}import{createHash as ln}from"node:crypto";import{createReadStream as Qo,readdirSync as Jo,statSync as xt}from"node:fs";import{join as Yo,relative as Zo}from"node:path";async function si(e,t={}){let n=t.algorithm||"sha256",r=t.chunkSize||65536;return new Promise((i,s)=>{let a=ln(n),o=Qo(e,{highWaterMark:r});o.on("data",(c)=>a.update(c)),o.on("end",()=>i(a.digest("hex"))),o.on("error",s)})}function ai(e,t="sha256"){return ln(t).update(e).digest("hex")}function Wy(e,t="sha256"){return ln(t).update(e).digest("hex")}async function Vy(e,t={}){let n=t.ignorePatterns||["node_modules",".git","dist","build",Fe()],r=[];async function i(s){let a=Jo(s,{withFileTypes:!0});for(let o of a){let c=Yo(s,o.name),l=Zo(e,c);if(n.some((u)=>l.includes(u)))continue;if(o.isDirectory())await i(c);else if(o.isFile()){let u=xt(c),m=await si(c,t);r.push({path:l,hash:m,size:u.size,mtime:u.mtimeMs})}}}return await i(e),r}function Uy(e){let n=[...e].sort((r,i)=>r.path.localeCompare(i.path)).map((r)=>`${r.path}:${r.hash}`).join(`
2498
+ `);return ai(n)}function Hy(e){let t=xt(e);return ai(`${e}:${t.size}:${t.mtimeMs}`)}function jy(e,t){let n=new Map(e.map((o)=>[o.path,o])),r=new Map(t.map((o)=>[o.path,o])),i=[],s=[],a=[];for(let[o,c]of r){let l=n.get(o);if(!l)i.push(c);else if(l.hash!==c.hash)s.push(c)}for(let[o,c]of n)if(!r.has(o))a.push(c);return{added:i,modified:s,deleted:a}}class Xo{cache;constructor(){this.cache=new Map}get(e){let t=xt(e),n=this.cache.get(e);if(n&&n.mtime===t.mtimeMs&&n.size===t.size)return n.hash;return}set(e,t){let n=xt(e);this.cache.set(e,{hash:t,mtime:n.mtimeMs,size:n.size})}async getOrCompute(e,t={}){let n=this.get(e);if(n)return n;let r=await si(e,t);return this.set(e,r),r}clear(){this.cache.clear()}}async function un(e,t={}){let n=t.concurrency||5,r=t.stopOnError??!0,i=[],s=[],a=Date.now(),o=[...e],c=[];async function l(p,g){try{let y=await p();i[g]=y}catch(y){let h=y instanceof Error?y:Error(String(y));if(s.push(h),r)throw o.length=0,h}}let u=0;while(o.length>0||c.length>0){while(c.length<n&&o.length>0){let p=o.shift(),g=u++,y=l(p,g);c.push(y)}if(c.length>0){await Promise.race(c);for(let p=c.length-1;p>=0;p--)if(await Promise.race([c[p].then(()=>!0),Promise.resolve(!1)]))c.splice(p,1)}if(r&&s.length>0)break}let m=Date.now()-a;return{results:i.filter((p)=>p!==void 0),errors:s,duration:m}}async function qy(e,t,n={}){let r=e.map((i)=>()=>t(i));return un(r,n)}async function zy(e,t,n=5){let r=e.map((s,a)=>()=>t(s,a)),i=await un(r,{concurrency:n,stopOnError:!1});if(i.errors.length>0)throw AggregateError(i.errors,"Parallel map failed");return i.results}async function Qy(e,t={}){let n=t.retries||3,r=t.retryDelay||1000,i=e.map((s)=>async()=>{let a;for(let o=0;o<=n;o++)try{return await s()}catch(c){if(a=c instanceof Error?c:Error(String(c)),o<n)await oi(r*(o+1))}throw a});return un(i,t)}async function Jy(e){let t=[];for(let n of e){let r=await n();t.push(r)}return t}function oi(e){return new Promise((t)=>setTimeout(t,e))}async function Yy(e,t,n="Operation timed out"){return Promise.race([e(),new Promise((r,i)=>setTimeout(()=>i(Error(n)),t))])}class ec{maxConcurrent;minInterval;queue=[];running=0;lastExecution=0;constructor(e=5,t=100){this.maxConcurrent=e;this.minInterval=t}async execute(e){await this.waitForSlot(),this.running++,this.lastExecution=Date.now();try{return await e()}finally{this.running--,this.processQueue()}}waitForSlot(){if(this.running<this.maxConcurrent){let e=Date.now()-this.lastExecution;if(e>=this.minInterval)return Promise.resolve();return oi(this.minInterval-e)}return new Promise((e)=>this.queue.push(e))}processQueue(){if(this.queue.length>0&&this.running<this.maxConcurrent)this.queue.shift()()}stats(){return{running:this.running,queued:this.queue.length}}}function tc(e,t){let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}async function Zy(e,t,n){let r=tc(e,t),i=[];for(let s of r){let a=await n(s);i.push(...a)}return i}function ef(e,t){let n=[],r=[],i=[],s=[],a=e.Resources||{},o=t.Resources||{},c=new Set(Object.keys(a)),l=new Set(Object.keys(o));for(let p of l)if(!c.has(p))n.push(p);for(let p of c)if(!l.has(p))i.push(p);for(let p of l)if(c.has(p)){let g=a[p],y=o[p];if(JSON.stringify(g)!==JSON.stringify(y))r.push(p);else s.push(p)}let u=JSON.stringify(e.Parameters||{})!==JSON.stringify(t.Parameters||{}),m=JSON.stringify(e.Outputs||{})!==JSON.stringify(t.Outputs||{});return{added:n,modified:r,deleted:i,unchanged:s,parametersChanged:u,outputsChanged:m,hasChanges:n.length>0||r.length>0||i.length>0||u||m}}function tf(e){let t=[];if(!e.hasChanges)return"No changes detected";if(e.added.length>0){t.push(`Added resources (${e.added.length}):`);for(let n of e.added)t.push(` + ${n}`)}if(e.modified.length>0){t.push(`Modified resources (${e.modified.length}):`);for(let n of e.modified)t.push(` ~ ${n}`)}if(e.deleted.length>0){t.push(`Deleted resources (${e.deleted.length}):`);for(let n of e.deleted)t.push(` - ${n}`)}if(e.parametersChanged)t.push("Parameters changed");if(e.outputsChanged)t.push("Outputs changed");return t.join(`
2499
2499
  `)}function nf(e,t,n){if(e.deleted.length>0)return!0;for(let r of e.modified){let i=t.Resources[r],s=n.Resources[r];if(i.Type!==s.Type)return!0;let a=nc(s.Type);for(let o of a){let c=i.Properties?.[o],l=s.Properties?.[o];if(JSON.stringify(c)!==JSON.stringify(l))return!0}}return!1}function nc(e){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"]}[e]||[]}function rf(e){let t=[],n=[],r=[];t.push(...e.added);for(let i of e.modified)n.push(i);return r.push(...e.deleted),{safe:t,caution:n,dangerous:r}}function sf(e){if(!e.hasChanges)return{strategy:"skip",reason:"No changes detected"};if(e.deleted.length>0)return{strategy:"replace",reason:"Resources will be deleted"};if(e.added.length>0&&e.modified.length===0)return{strategy:"update",reason:"Only new resources added"};return{strategy:"update",reason:"Resources will be updated"}}function af(e){let t=e.added.length+e.modified.length+e.deleted.length+e.unchanged.length,n=e.added.length+e.modified.length+e.deleted.length,r=t>0?n/t*100:0;return{total:t,added:e.added.length,modified:e.modified.length,deleted:e.deleted.length,unchanged:e.unchanged.length,changePercentage:r}}var ic={$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 uf(e){let t=[];if(!e.project)t.push("Missing required field: project");else{if(!e.project.name)t.push("Missing required field: project.name");if(!e.project.slug)t.push("Missing required field: project.slug")}if(e.project?.slug&&!/^[a-z0-9-]+$/.test(e.project.slug))t.push("Invalid project.slug: must contain only lowercase letters, numbers, and hyphens");let n=["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(e.project?.region&&!n.includes(e.project.region))t.push(`Invalid region: ${e.project.region}. Must be one of: ${n.join(", ")}`);if(e.mode&&!["server","serverless"].includes(e.mode))t.push("Invalid mode: must be one of server or serverless");return{valid:t.length===0,errors:t}}var ci={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 dn(){return ci}function mf(){return ci.enabled}function pf(e){let t=dn();if(!t.enabled)return"";switch(e.toLowerCase()){case"dynamodb":return t.dynamodbEndpoint;case"s3":return t.s3Endpoint;case"localstack":case"cloudformation":case"lambda":case"apigateway":case"sns":case"sqs":case"cloudwatch":case"iam":case"sts":return t.localstackEndpoint;default:return t.localstackEndpoint}}function gf(){let e=dn();return{accessKeyId:e.awsAccessKeyId,secretAccessKey:e.awsSecretAccessKey,region:e.awsRegion}}function yf(){let e=dn();if(!e.enabled)return{};return{AWS_ACCESS_KEY_ID:e.awsAccessKeyId,AWS_SECRET_ACCESS_KEY:e.awsSecretAccessKey,AWS_REGION:e.awsRegion,AWS_ENDPOINT_URL:e.localstackEndpoint,LOCALSTACK_ENDPOINT:e.localstackEndpoint,TS_CLOUD_LOCAL:"true"}}class li{stacks=new Map;stackEvents=new Map;async createStack(e){let t=`arn:aws:cloudformation:${e.region||"us-east-1"}:123456789012:stack/${e.StackName}/${Date.now()}`;return this.stacks.set(e.StackName,{StackId:t,StackName:e.StackName,StackStatus:"CREATE_IN_PROGRESS",CreationTime:new Date().toISOString(),TemplateBody:e.TemplateBody,Parameters:e.Parameters||[]}),this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_IN_PROGRESS"}),setTimeout(()=>{let n=this.stacks.get(e.StackName);if(n)n.StackStatus="CREATE_COMPLETE",this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_COMPLETE"})},100),{StackId:t}}async updateStack(e){let t=this.stacks.get(e.StackName);if(!t)throw Error(`Stack ${e.StackName} does not exist`);return t.StackStatus="UPDATE_IN_PROGRESS",t.TemplateBody=e.TemplateBody||t.TemplateBody,this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_IN_PROGRESS"}),setTimeout(()=>{t.StackStatus="UPDATE_COMPLETE",this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_COMPLETE"})},100),{StackId:t.StackId}}async deleteStack(e){let t=this.stacks.get(e.StackName);if(!t)throw Error(`Stack ${e.StackName} does not exist`);t.StackStatus="DELETE_IN_PROGRESS",this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_IN_PROGRESS"}),setTimeout(()=>{this.stacks.delete(e.StackName),this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_COMPLETE"})},100)}async describeStacks(e){if(e.StackName){let t=this.stacks.get(e.StackName);if(!t)throw Error(`Stack ${e.StackName} does not exist`);return{Stacks:[t]}}return{Stacks:Array.from(this.stacks.values())}}async describeStackEvents(e){return{StackEvents:this.stackEvents.get(e.StackName)||[]}}addEvent(e,t){if(!this.stackEvents.has(e))this.stackEvents.set(e,[]);this.stackEvents.get(e).unshift(t)}reset(){this.stacks.clear(),this.stackEvents.clear()}}class ui{buckets=new Map;async createBucket(e){return this.buckets.set(e.Bucket,new Map),{Location:`/${e.Bucket}`}}async deleteBucket(e){this.buckets.delete(e.Bucket)}async putObject(e){let t=this.buckets.get(e.Bucket);if(!t)t=new Map,this.buckets.set(e.Bucket,t);return t.set(e.Key,Buffer.from(e.Body||"")),{ETag:`"${Date.now()}"`}}async getObject(e){let t=this.buckets.get(e.Bucket);if(!t)throw Error(`Bucket ${e.Bucket} does not exist`);let n=t.get(e.Key);if(!n)throw Error(`Object ${e.Key} does not exist`);return{Body:n,ContentLength:n.length}}async deleteObject(e){let t=this.buckets.get(e.Bucket);if(t)t.delete(e.Key)}async listObjects(e){let t=this.buckets.get(e.Bucket);if(!t)throw Error(`Bucket ${e.Bucket} does not exist`);return{Contents:Array.from(t.keys()).map((r)=>({Key:r,Size:t.get(r).length,LastModified:new Date().toISOString()}))}}reset(){this.buckets.clear()}}class di{tables=new Map;data=new Map;async createTable(e){return this.tables.set(e.TableName,{TableName:e.TableName,KeySchema:e.KeySchema,AttributeDefinitions:e.AttributeDefinitions,TableStatus:"ACTIVE",CreationDateTime:new Date().toISOString()}),this.data.set(e.TableName,new Map),{TableDescription:this.tables.get(e.TableName)}}async deleteTable(e){this.tables.delete(e.TableName),this.data.delete(e.TableName)}async putItem(e){let t=this.data.get(e.TableName);if(!t)t=new Map,this.data.set(e.TableName,t);let n=JSON.stringify(e.Item);t.set(n,e.Item)}async getItem(e){let t=this.data.get(e.TableName);if(!t)return{};let n=JSON.stringify(e.Key),r=t.get(n);return r?{Item:r}:{}}async deleteItem(e){let t=this.data.get(e.TableName);if(t){let n=JSON.stringify(e.Key);t.delete(n)}}async scan(e){let t=this.data.get(e.TableName);if(!t)return{Items:[]};return{Items:Array.from(t.values())}}reset(){this.tables.clear(),this.data.clear()}}function hf(e){return{cloudformation:new li,s3:new ui,dynamodb:new di}}class mn{environments=new Map;async createPreviewEnvironment(e){let{branch:t,pr:n,commitSha:r,ttl:i=24,baseConfig:s,region:a="us-east-1"}=e,o=this.generatePreviewId(t,n,r),c=this.generatePreviewName(t,n),l=`preview-${c}`,u=new Date,m=new Date(u.getTime()+i*60*60*1000),p={id:o,name:c,branch:t,pr:n,commitSha:r,createdAt:u,expiresAt:m,status:"creating",stackName:l,region:a,resources:[]};this.environments.set(o,p);try{let g=this.createPreviewConfig(s,c);return p.status="active",p.url=`https://${c}.preview.example.com`,p}catch(g){throw p.status="failed",g}}async destroyPreviewEnvironment(e){let t=this.environments.get(e);if(!t)throw Error(`Preview environment ${e} not found`);t.status="destroying";try{t.status="destroyed",this.environments.delete(e)}catch(n){throw Error(`Failed to destroy preview environment: ${n}`)}}getPreviewEnvironment(e){return this.environments.get(e)}getPreviewEnvironmentByBranch(e){return Array.from(this.environments.values()).find((t)=>t.branch===e)}getPreviewEnvironmentByPR(e){return Array.from(this.environments.values()).find((t)=>t.pr===e)}listPreviewEnvironments(){return Array.from(this.environments.values())}listActivePreviewEnvironments(){return this.listPreviewEnvironments().filter((e)=>e.status==="active")}async cleanupExpiredEnvironments(e={}){let{maxAge:t,keepCount:n,dryRun:r=!1}=e,i=[],s=[],a=new Date,o=this.listPreviewEnvironments().sort((c,l)=>l.createdAt.getTime()-c.createdAt.getTime());for(let c=0;c<o.length;c++){let l=o[c];if(l.status!=="active")continue;let u=!1;if(l.expiresAt<a)u=!0;if(t){if((a.getTime()-l.createdAt.getTime())/3600000>t)u=!0}if(n&&c>=n)u=!0;if(u)if(r)i.push(l.id);else try{await this.destroyPreviewEnvironment(l.id),i.push(l.id)}catch(m){s.push(l.id)}}return{destroyed:i,failed:s}}async updatePreviewEnvironment(e,t){let n=this.environments.get(e);if(!n)throw Error(`Preview environment ${e} not found`);n.commitSha=t,n.status="creating";try{return n.status="active",n}catch(r){throw n.status="failed",r}}async getPreviewEnvironmentsCost(){let e={},t=0;for(let n of this.environments.values())e[n.id]=0,t+=0;return{total:t,byEnvironment:e}}generatePreviewId(e,t,n){let r=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase(),i=n?.substring(0,7)||Date.now().toString();return t?`pr-${t}-${i}`:`${r}-${i}`}generatePreviewName(e,t){let n=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase();return t?`pr-${t}`:n}createPreviewConfig(e,t){return{...e,project:{...e.project,name:`${e.project.name} Preview (${t})`,slug:`${e.project.slug}-preview-${t}`}}}}var sc=new mn;function ac(e={}){let{workflowName:t="Preview Environment",trigger:n="pull_request",branches:r=["main","develop"],awsRegion:i="us-east-1",awsRole:s,configFile:a="cloud.config.ts",ttl:o=24}=e;return`name: ${t}
2500
2500
 
2501
2501
  on:
@@ -2748,8 +2748,8 @@ ${t.map((n)=>` • ${n}`).join(`
2748
2748
  `))}catch(e){console.error(`Failed to save history: ${e}`)}}searchHistory(e){return this.history.commands.filter((t)=>t.includes(e))}clearHistory(){this.history.commands=[],this.historyIndex=0}}class Sc{variables=new Map;workingDirectory=process.cwd();set(e,t){this.variables.set(e,t)}get(e){return this.variables.get(e)}has(e){return this.variables.has(e)}delete(e){this.variables.delete(e)}getAll(){return Object.fromEntries(this.variables)}clear(){this.variables.clear()}setWorkingDirectory(e){this.workingDirectory=e}getWorkingDirectory(){return this.workingDirectory}}class Ac{command={};name(e){return this.command.name=e,this}description(e){return this.command.description=e,this}aliases(...e){return this.command.aliases=e,this}handler(e){return this.command.handler=e,this}autocomplete(e){return this.command.autocomplete=e,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 Cc{entries=[];maxSize;persistFile;trackOutput;constructor(e={}){this.maxSize=e.maxSize||1000,this.persistFile=e.persistFile,this.trackOutput=e.trackOutput||!1}add(e){if(this.entries.push({...e,timestamp:new Date}),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}getAll(){return[...this.entries]}getRecent(e=10){return this.entries.slice(-e)}search(e){let t=e.toLowerCase();return this.entries.filter((n)=>n.command.toLowerCase().includes(t))}searchByDate(e,t){return this.entries.filter((n)=>n.timestamp>=e&&n.timestamp<=t)}getSuccessful(){return this.entries.filter((e)=>e.success)}getFailed(){return this.entries.filter((e)=>!e.success)}getMostUsed(e=10){let t=new Map;for(let n of this.entries){let r=n.command.split(" ")[0];t.set(r,(t.get(r)||0)+1)}return Array.from(t.entries()).map(([n,r])=>({command:n,count:r})).sort((n,r)=>r.count-n.count).slice(0,e)}getStats(){let e=this.entries.length,t=this.entries.filter((o)=>o.success).length,n=this.entries.filter((o)=>!o.success).length,r=this.entries.filter((o)=>o.duration!==void 0),i=r.length>0?r.reduce((o,c)=>o+(c.duration||0),0)/r.length:0,s=this.getMostUsed(1),a=s.length>0?s[0].command:"N/A";return{total:e,successful:t,failed:n,averageDuration:i,mostUsed:a}}clear(){this.entries=[]}getByIndex(e){if(e<0||e>=this.entries.length)return;return this.entries[e]}removeByIndex(e){if(e>=0&&e<this.entries.length)this.entries.splice(e,1)}async save(){if(!this.persistFile)return;try{let e=await import("node:fs/promises"),t=JSON.stringify(this.entries,null,2);await e.writeFile(this.persistFile,t,"utf-8")}catch(e){throw Error(`Failed to save history: ${e}`)}}async load(){if(!this.persistFile)return;try{let e=await import("node:fs/promises"),t=await e.readFile(this.persistFile,"utf-8"),n=JSON.parse(t);this.entries=n.map((r)=>({...r,timestamp:new Date(r.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(`
2749
2749
  `)}importJSON(e){let n=JSON.parse(e).map((r)=>({...r,timestamp:new Date(r.timestamp)}));if(this.entries.push(...n),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}groupByDate(){let e=new Map;for(let t of this.entries){let n=t.timestamp.toISOString().split("T")[0];if(!e.has(n))e.set(n,[]);e.get(n).push(t)}return e}groupByCommand(){let e=new Map;for(let t of this.entries){let n=t.command.split(" ")[0];if(!e.has(n))e.set(n,[]);e.get(n).push(t)}return e}replay(e){return this.getByIndex(e)?.command}getSuggestions(e,t=5){let n=e.toLowerCase(),r=this.entries.filter((i)=>i.command.toLowerCase().startsWith(n)).map((i)=>i.command);return[...new Set(r)].slice(0,t)}analyzePatterns(){let e=new Map,t=new Map;for(let r of this.entries){let i=r.timestamp.getHours(),s=r.timestamp.getDay();e.set(i,(e.get(i)||0)+1),t.set(s,(t.get(s)||0)+1)}let n=this.entries.length>0?this.getSuccessful().length/this.entries.length:0;return{timeOfDay:e,dayOfWeek:t,successRate:n}}}function Kf(e,t={}){let{maxWidth:n=100}=t;if(e.length===0)return"No command history";let r=[];for(let i=0;i<e.length;i++){let s=e[i],a=(i+1).toString().padStart(4),o=s.timestamp.toLocaleString(),c=s.success?"✓":"✗",l=s.command;if(l.length>n-30)l=l.substring(0,n-33)+"...";let u=`${a} ${o} ${c} ${l}`;if(s.duration)u+=` (${s.duration}ms)`;r.push(u)}return r.join(`
2750
2750
  `)}function qf(e){let t=[];return t.push("Command History Statistics"),t.push("─".repeat(30)),t.push(`Total commands: ${e.total}`),t.push(`Successful: ${e.successful}`),t.push(`Failed: ${e.failed}`),t.push(`Success rate: ${(e.successful/e.total*100).toFixed(1)}%`),t.push(`Average duration: ${e.averageDuration.toFixed(0)}ms`),t.push(`Most used: ${e.mostUsed}`),t.join(`
2751
- `)}class yi{deployments=new Map;async deploy(e,t){let n=this.generateDeploymentId(),r={id:n,regions:t.regions.map((i)=>({region:i.code,stackName:this.getStackName(e,i.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(n,r);try{let i=t.regions.find((a)=>a.isPrimary)||t.regions[0];await this.deployToRegion(e,i,r);let s=t.regions.filter((a)=>a.code!==i.code);if(await Promise.all(s.map((a)=>this.deployToRegion(e,a,r))),t.globalResources)await this.deployGlobalResources(r,t);if(t.replication)await this.setupReplication(r,t);if(t.failover?.enabled)await this.setupFailover(r,t);return r.status="deployed",r.endTime=new Date,r}catch(i){throw r.status="failed",r.endTime=new Date,i}}async deployToRegion(e,t,n){let r=n.regions.find((i)=>i.region===t.code);if(!r)throw Error(`Region deployment not found: ${t.code}`);r.status="deploying",r.startTime=new Date;try{let i=this.createRegionConfig(e,t);await this.deployStack(r.stackName,i,t.code),r.status="deployed",r.endTime=new Date,r.outputs={stackId:`arn:aws:cloudformation:${t.code}:123456789012:stack/${r.stackName}/guid`,endpoint:`https://${r.stackName}.${t.code}.example.com`}}catch(i){throw r.status="failed",r.endTime=new Date,r.error=i instanceof Error?i.message:String(i),i}}async deployGlobalResources(e,t){let n={};if(t.globalResources?.route53)n.route53=await this.deployRoute53(e,t);if(t.globalResources?.cloudfront)n.cloudfront=await this.deployCloudFront(e,t);if(t.globalResources?.waf)n.waf=await this.deployWAF(e);e.globalResources=n}async deployRoute53(e,t){let n=[],r=[];for(let i of e.regions){if(i.status!=="deployed")continue;let s={id:`health-${i.region}`,endpoint:i.outputs?.endpoint,path:t.failover?.healthCheckPath||"/health",region:i.region};n.push(s);let a={name:"example.com",type:"A",region:i.region,setIdentifier:i.region,healthCheckId:s.id,resourceRecords:[i.outputs?.endpoint]};r.push(a)}return{healthChecks:n,recordSets:r,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(e,t){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:e.regions.filter((r)=>r.status==="deployed").map((r,i)=>{let s=t.regions[i];return{id:`origin-${r.region}`,domainName:r.outputs?.endpoint,weight:s?.weight||100}}),status:"Deployed"}}async deployWAF(e){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(e,t){if(t.replication?.s3)await this.setupS3Replication(e);if(t.replication?.dynamodb)await this.setupDynamoDBReplication(e);if(t.replication?.secrets)await this.setupSecretsReplication(e)}async setupS3Replication(e){let t=e.regions.filter((n)=>n.status==="deployed");for(let n=0;n<t.length-1;n++){let r=t[n],i=t[n+1];console.log(`Setting up S3 replication: ${r.region} -> ${i.region}`)}}async setupDynamoDBReplication(e){let t=e.regions.filter((n)=>n.status==="deployed").map((n)=>n.region);console.log(`Setting up DynamoDB global table in regions: ${t.join(", ")}`)}async setupSecretsReplication(e){let t=e.regions.filter((n)=>n.status==="deployed").map((n)=>n.region);console.log(`Setting up Secrets Manager replication in regions: ${t.join(", ")}`)}async setupFailover(e,t){let n=e.regions.find((i,s)=>t.regions[s]?.isPrimary)||e.regions[0],r=e.regions.filter((i)=>i.region!==n.region);console.log(`Setting up failover: primary=${n.region}, secondary=${r.map((i)=>i.region).join(", ")}`)}async destroy(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);t.status="rolling-back";try{if(t.globalResources)await this.destroyGlobalResources(t.globalResources);await Promise.all(t.regions.map((n)=>this.destroyRegionStack(n))),this.deployments.delete(e)}catch(n){throw t.status="failed",n}}async destroyGlobalResources(e){if(e.waf)console.log("Destroying WAF resources");if(e.cloudfront)console.log("Destroying CloudFront distribution");if(e.route53)console.log("Destroying Route53 resources")}async destroyRegionStack(e){if(e.status!=="deployed")return;e.status="rolling-back";try{console.log(`Destroying stack ${e.stackName} in ${e.region}`),e.status="pending"}catch(t){throw e.status="failed",e.error=t instanceof Error?t.message:String(t),t}}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getStackName(e,t){return`${e.project.slug}-${t}`}createRegionConfig(e,t){return{...e,infrastructure:{...e.infrastructure}}}async deployStack(e,t,n){console.log(`Deploying stack ${e} to ${n}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var th=new yi;class fi{references=[];exports=new Map;addExport(e){let t=`${e.region}:${e.exportName}`;if(!this.exports.has(e.region))this.exports.set(e.region,[]);this.exports.get(e.region).push(e)}getExport(e,t){let n=this.exports.get(e);if(!n)return;return n.find((i)=>i.exportName===t)?.value}createReference(e,t,n,r){let i=`/cross-region/${e}/${n}/${r}`;return this.references.push({sourceRegion:e,targetRegion:t,resourceType:n,resourceId:r,value:i}),i}async resolveReference(e,t){let n=this.references.find((r)=>r.targetRegion===e&&r.value===t);if(!n)throw Error(`Reference not found: ${t}`);return`arn:aws:resource:${n.sourceRegion}:123456789012:${n.resourceType}/${n.resourceId}`}getReferencesForRegion(e){return this.references.filter((t)=>t.sourceRegion===e||t.targetRegion===e)}clear(){this.references=[],this.exports.clear()}}class hi{resources=new Map;register(e){this.resources.set(e.id,e)}get(e){return this.resources.get(e)}getByType(e){return Array.from(this.resources.values()).filter((t)=>t.type===e)}getCloudFrontDistributions(){return this.getByType("cloudfront")}getRoute53HostedZones(){return this.getByType("route53")}getWAFWebACLs(){return this.getByType("waf")}remove(e){this.resources.delete(e)}clear(){this.resources.clear()}}class bi{pairs=[];addPair(e){this.pairs.push(e)}getPairedRegion(e){let t=this.pairs.find((n)=>n.primary===e||n.secondary===e);if(!t)return;return t.primary===e?t.secondary:t.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((e)=>e.replicationConfig)}getFailoverPairs(){return this.pairs.filter((e)=>e.failoverConfig?.automatic)}arePaired(e,t){return this.pairs.some((n)=>n.primary===e&&n.secondary===t||n.primary===t&&n.secondary===e)}clear(){this.pairs=[]}}class Si{dependencies=[];addDependency(e){this.dependencies.push(e)}getDependencies(e,t){return this.dependencies.filter((n)=>n.dependentStack===e&&n.dependentRegion===t)}getDependents(e,t){return this.dependencies.filter((n)=>n.dependsOnStack===e&&n.dependsOnRegion===t)}hasDependencies(e,t){return this.getDependencies(e,t).length>0}getDeploymentOrder(e){let t=new Set,n=[],r=(i)=>{let s=`${i.name}:${i.region}`;if(t.has(s))return;t.add(s);let a=this.getDependencies(i.name,i.region);for(let o of a)r({name:o.dependsOnStack,region:o.dependsOnRegion});n.push(i)};for(let i of e)r(i);return n}detectCircularDependencies(){let e=new Set,t=new Set,n=(r,i)=>{let s=`${r}:${i}`;if(t.has(s))return!0;if(e.has(s))return!1;e.add(s),t.add(s);let a=this.getDependencies(r,i);for(let o of a)if(n(o.dependsOnStack,o.dependsOnRegion))return!0;return t.delete(s),!1};for(let r of this.dependencies)if(n(r.dependentStack,r.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var rh=new fi,ih=new hi,sh=new bi,ah=new Si;var le=[{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 ut(e){return le.find((t)=>t.code===e)}function ch(){return le}function lh(e){let t=e.toLowerCase();return le.filter((n)=>n.location.toLowerCase().includes(t))}function uh(e){return le.filter((t)=>t.compliance.includes(e))}function dh(e){return le.filter((t)=>t.pricing.tier===e)}function mh(e){return le.some((t)=>t.code===e)}function ph(e){if(e.continent==="North America")return ut("us-east-1");if(e.continent==="Europe")return ut("eu-west-1");if(e.continent==="Asia")return ut("ap-southeast-1");return ut("us-east-1")}function gh(e){let t=[...le];if(e.compliance)t=t.filter((n)=>e.compliance.every((r)=>n.compliance.includes(r)));if(e.requiredServices)t=t.filter((n)=>e.requiredServices.every((r)=>n.services[r]));if(e.pricingSensitive)t.sort((n,r)=>n.pricing.multiplier-r.pricing.multiplier);return t.slice(0,5)}function yh(e){let t=ut(e);if(!t)throw Error(`Invalid region: ${e}`);let n=[];for(let r of le){if(r.code===e)continue;let i=vc(t,r),s=Tc(t,r);n.push({primary:t,secondary:r,distance:i,sameContinent:s})}return n.sort((r,i)=>{if(r.sameContinent!==i.sameContinent)return r.sameContinent?1:-1;return r.distance-i.distance}),n.slice(0,3)}function vc(e,t){let n={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},r=dt(e.location),i=dt(t.location);return Math.abs((n[r]||0)-(n[i]||0))}function Tc(e,t){return dt(e.location)===dt(t.location)}function dt(e){if(e.includes("USA")||e.includes("Canada"))return"North America";if(e.includes("Europe")||e.includes("Ireland")||e.includes("Germany"))return"Europe";if(e.includes("Asia")||e.includes("Singapore")||e.includes("Japan"))return"Asia";if(e.includes("Brazil"))return"South America";if(e.includes("Australia"))return"Oceania";return"Unknown"}function Rc(e){return`${e.name} (${e.code})`}function fh(e){return e.map((t)=>Rc(t)).join(`
2752
- `)}function hh(){let e={total:le.length,byContinent:{},byPricingTier:{}};for(let t of le){let n=dt(t.location);e.byContinent[n]=(e.byContinent[n]||0)+1,e.byPricingTier[t.pricing.tier]=(e.byPricingTier[t.pricing.tier]||0)+1}return e}class Ai{accounts=new Map;crossAccountRoles=[];accountMappings=[];registerAccount(e){this.accounts.set(e.id,e)}getAccount(e){return this.accounts.get(e)}getAccountByAlias(e){return Array.from(this.accounts.values()).find((t)=>t.alias===e)}listAccounts(){return Array.from(this.accounts.values())}getAccountsByRole(e){return Array.from(this.accounts.values()).filter((t)=>t.role===e)}createCrossAccountRole(e,t,n,r,i){let s={roleArn:`arn:aws:iam::${t}:role/${n}`,roleName:n,sourceAccountId:e,targetAccountId:t,permissions:r,externalId:i?.externalId,sessionDuration:i?.sessionDuration||3600};return this.crossAccountRoles.push(s),s}getAssumeRolePolicyDocument(e,t){let n={Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e}:root`},Action:"sts:AssumeRole"}]};if(t)n.Statement[0].Condition={StringEquals:{"sts:ExternalId":t}};return n}generateCrossAccountPolicy(e){return{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e,Resource:"*"}]}}mapEnvironmentToAccount(e,t,n){this.accountMappings.push({environment:e,accountId:t,region:n})}getAccountForEnvironment(e){return this.accountMappings.find((t)=>t.environment===e)}async assumeRole(e,t,n){return console.log(`Assuming role: ${e} with session: ${t}`),{accessKeyId:"AKIAIOSFODNN7EXAMPLE",secretAccessKey:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",sessionToken:"token",expiration:new Date(Date.now()+3600000)}}async getCredentialsForAccount(e){let t=this.accounts.get(e);if(!t)throw Error(`Account not found: ${e}`);if(t.assumeRoleArn){let n=await this.assumeRole(t.assumeRoleArn,`ts-cloud-${Date.now()}`);return{accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,sessionToken:n.sessionToken}}throw Error("No credentials available for account")}listCrossAccountRoles(){return[...this.crossAccountRoles]}getCrossAccountRolesForAccount(e){return this.crossAccountRoles.filter((t)=>t.sourceAccountId===e||t.targetAccountId===e)}async validateAccountAccess(e){try{let t=await this.getCredentialsForAccount(e);return console.log(`Validating access to account: ${e}`),!0}catch{return!1}}async getConsolidatedBilling(){let e={};for(let n of this.accounts.values())e[n.id]=Math.random()*1000;return{totalCost:Object.values(e).reduce((n,r)=>n+r,0),byAccount:e}}clear(){this.accounts.clear(),this.crossAccountRoles=[],this.accountMappings=[]}}class Ci{organizationId;organizationalUnits=new Map;getOrganizationId(){return this.organizationId}setOrganizationId(e){this.organizationId=e}createOrganizationalUnit(e,t){let n={id:`ou-${Date.now()}`,name:e,parentId:t,accounts:[]};return this.organizationalUnits.set(n.id,n),n}getOrganizationalUnit(e){return this.organizationalUnits.get(e)}listOrganizationalUnits(){return Array.from(this.organizationalUnits.values())}addAccountToOU(e,t){let n=this.organizationalUnits.get(e);if(!n)throw Error(`Organizational unit not found: ${e}`);if(!n.accounts.includes(t))n.accounts.push(t)}removeAccountFromOU(e,t){let n=this.organizationalUnits.get(e);if(!n)throw Error(`Organizational unit not found: ${e}`);n.accounts=n.accounts.filter((r)=>r!==t)}getAccountsInOU(e){let t=this.organizationalUnits.get(e);if(!t)return[];return[...t.accounts]}applyServiceControlPolicy(e,t){return{id:`scp-${Date.now()}`,name:"Custom SCP",targetId:e,policyDocument:t}}clear(){this.organizationId=void 0,this.organizationalUnits.clear()}}var Th=new Ai,Rh=new Ci;var Pc={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"}]}},Eh={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"]}}}]}}},wh={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 Ih(e){return Pc[e]}function Dh(e,t){return{Type:"AWS::IAM::Role",Properties:{RoleName:e.roleName,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e.sourceAccountId}:root`},Action:"sts:AssumeRole",...e.externalId&&{Condition:{StringEquals:{"sts:ExternalId":e.externalId}}}}]},Policies:[{PolicyName:`${e.roleName}Policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e.permissions,Resource:"*"}]}}],...t&&{ManagedPolicyArns:t},MaxSessionDuration:e.sessionDuration||3600,Tags:[{Key:"ManagedBy",Value:"TS-Cloud"},{Key:"SourceAccount",Value:e.sourceAccountId}]}}}function Nh(e){let t=[],n=[],r=e.accounts.filter((c)=>c.role==="management");if(r.length===0)t.push("No management account defined");if(r.length>1)t.push("Multiple management accounts defined");let i=e.accounts.map((c)=>c.email),s=i.filter((c,l)=>i.indexOf(c)!==l);if(s.length>0)t.push(`Duplicate email addresses: ${s.join(", ")}`);let a=e.accounts.map((c)=>c.alias),o=a.filter((c,l)=>a.indexOf(c)!==l);if(o.length>0)t.push(`Duplicate aliases: ${o.join(", ")}`);if(!e.accounts.some((c)=>c.role==="security"))n.push("No dedicated security account - consider adding one for audit logs");if(e.accounts.length<3)n.push("Less than 3 accounts - consider separating environments");if(!e.accounts.some((c)=>c.role==="production"))n.push("No production account defined");return{valid:t.length===0,errors:t,warnings:n}}function xh(e){let t=[];if(t.push(`${e.name}`),t.push("─".repeat(e.name.length)),t.push(e.description),t.push(""),e.organizationalUnits){t.push("Organizational Units:");for(let n of e.organizationalUnits){let r=n.parent?" └─ ":" ";t.push(`${r}${n.name}`)}t.push("")}t.push("Accounts:");for(let n of e.accounts)t.push(` ${n.alias.padEnd(20)} ${n.role.padEnd(15)} ${n.email}`),t.push(` ${"".padEnd(20)} ${n.description}`),t.push("");return t.join(`
2751
+ `)}class yi{deployments=new Map;async deploy(e,t){let n=this.generateDeploymentId(),r={id:n,regions:t.regions.map((i)=>({region:i.code,stackName:this.getStackName(e,i.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(n,r);try{let i=t.regions.find((a)=>a.isPrimary)||t.regions[0];await this.deployToRegion(e,i,r);let s=t.regions.filter((a)=>a.code!==i.code);if(await Promise.all(s.map((a)=>this.deployToRegion(e,a,r))),t.globalResources)await this.deployGlobalResources(r,t);if(t.replication)await this.setupReplication(r,t);if(t.failover?.enabled)await this.setupFailover(r,t);return r.status="deployed",r.endTime=new Date,r}catch(i){throw r.status="failed",r.endTime=new Date,i}}async deployToRegion(e,t,n){let r=n.regions.find((i)=>i.region===t.code);if(!r)throw Error(`Region deployment not found: ${t.code}`);r.status="deploying",r.startTime=new Date;try{let i=this.createRegionConfig(e,t);await this.deployStack(r.stackName,i,t.code),r.status="deployed",r.endTime=new Date,r.outputs={stackId:`arn:aws:cloudformation:${t.code}:123456789012:stack/${r.stackName}/guid`,endpoint:`https://${r.stackName}.${t.code}.example.com`}}catch(i){throw r.status="failed",r.endTime=new Date,r.error=i instanceof Error?i.message:String(i),i}}async deployGlobalResources(e,t){let n={};if(t.globalResources?.route53)n.route53=await this.deployRoute53(e,t);if(t.globalResources?.cloudfront)n.cloudfront=await this.deployCloudFront(e,t);if(t.globalResources?.waf)n.waf=await this.deployWAF(e);e.globalResources=n}async deployRoute53(e,t){let n=[],r=[];for(let i of e.regions){if(i.status!=="deployed")continue;let s={id:`health-${i.region}`,endpoint:i.outputs?.endpoint,path:t.failover?.healthCheckPath||"/health",region:i.region};n.push(s);let a={name:"example.com",type:"A",region:i.region,setIdentifier:i.region,healthCheckId:s.id,resourceRecords:[i.outputs?.endpoint]};r.push(a)}return{healthChecks:n,recordSets:r,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(e,t){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:e.regions.filter((r)=>r.status==="deployed").map((r,i)=>{let s=t.regions[i];return{id:`origin-${r.region}`,domainName:r.outputs?.endpoint,weight:s?.weight||100}}),status:"Deployed"}}async deployWAF(e){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(e,t){if(t.replication?.s3)await this.setupS3Replication(e);if(t.replication?.dynamodb)await this.setupDynamoDBReplication(e);if(t.replication?.secrets)await this.setupSecretsReplication(e)}async setupS3Replication(e){let t=e.regions.filter((n)=>n.status==="deployed");for(let n=0;n<t.length-1;n++){let r=t[n],i=t[n+1];console.log(`Setting up S3 replication: ${r.region} -> ${i.region}`)}}async setupDynamoDBReplication(e){let t=e.regions.filter((n)=>n.status==="deployed").map((n)=>n.region);console.log(`Setting up DynamoDB global table in regions: ${t.join(", ")}`)}async setupSecretsReplication(e){let t=e.regions.filter((n)=>n.status==="deployed").map((n)=>n.region);console.log(`Setting up Secrets Manager replication in regions: ${t.join(", ")}`)}async setupFailover(e,t){let n=e.regions.find((i,s)=>t.regions[s]?.isPrimary)||e.regions[0],r=e.regions.filter((i)=>i.region!==n.region);console.log(`Setting up failover: primary=${n.region}, secondary=${r.map((i)=>i.region).join(", ")}`)}async destroy(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);t.status="rolling-back";try{if(t.globalResources)await this.destroyGlobalResources(t.globalResources);await Promise.all(t.regions.map((n)=>this.destroyRegionStack(n))),this.deployments.delete(e)}catch(n){throw t.status="failed",n}}async destroyGlobalResources(e){if(e.waf)console.log("Destroying WAF resources");if(e.cloudfront)console.log("Destroying CloudFront distribution");if(e.route53)console.log("Destroying Route53 resources")}async destroyRegionStack(e){if(e.status!=="deployed")return;e.status="rolling-back";try{console.log(`Destroying stack ${e.stackName} in ${e.region}`),e.status="pending"}catch(t){throw e.status="failed",e.error=t instanceof Error?t.message:String(t),t}}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getStackName(e,t){return`${e.project.slug}-${t}`}createRegionConfig(e,t){return{...e,infrastructure:{...e.infrastructure}}}async deployStack(e,t,n){console.log(`Deploying stack ${e} to ${n}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var th=new yi;class fi{references=[];exports=new Map;addExport(e){let t=`${e.region}:${e.exportName}`;if(!this.exports.has(e.region))this.exports.set(e.region,[]);this.exports.get(e.region).push(e)}getExport(e,t){let n=this.exports.get(e);if(!n)return;return n.find((i)=>i.exportName===t)?.value}createReference(e,t,n,r){let i=`/cross-region/${e}/${n}/${r}`;return this.references.push({sourceRegion:e,targetRegion:t,resourceType:n,resourceId:r,value:i}),i}async resolveReference(e,t){let n=this.references.find((r)=>r.targetRegion===e&&r.value===t);if(!n)throw Error(`Reference not found: ${t}`);return`arn:aws:resource:${n.sourceRegion}:123456789012:${n.resourceType}/${n.resourceId}`}getReferencesForRegion(e){return this.references.filter((t)=>t.sourceRegion===e||t.targetRegion===e)}clear(){this.references=[],this.exports.clear()}}class hi{resources=new Map;register(e){this.resources.set(e.id,e)}get(e){return this.resources.get(e)}getByType(e){return Array.from(this.resources.values()).filter((t)=>t.type===e)}getCloudFrontDistributions(){return this.getByType("cloudfront")}getRoute53HostedZones(){return this.getByType("route53")}getWAFWebACLs(){return this.getByType("waf")}remove(e){this.resources.delete(e)}clear(){this.resources.clear()}}class bi{pairs=[];addPair(e){this.pairs.push(e)}getPairedRegion(e){let t=this.pairs.find((n)=>n.primary===e||n.secondary===e);if(!t)return;return t.primary===e?t.secondary:t.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((e)=>e.replicationConfig)}getFailoverPairs(){return this.pairs.filter((e)=>e.failoverConfig?.automatic)}arePaired(e,t){return this.pairs.some((n)=>n.primary===e&&n.secondary===t||n.primary===t&&n.secondary===e)}clear(){this.pairs=[]}}class Si{dependencies=[];addDependency(e){this.dependencies.push(e)}getDependencies(e,t){return this.dependencies.filter((n)=>n.dependentStack===e&&n.dependentRegion===t)}getDependents(e,t){return this.dependencies.filter((n)=>n.dependsOnStack===e&&n.dependsOnRegion===t)}hasDependencies(e,t){return this.getDependencies(e,t).length>0}getDeploymentOrder(e){let t=new Set,n=[],r=(i)=>{let s=`${i.name}:${i.region}`;if(t.has(s))return;t.add(s);let a=this.getDependencies(i.name,i.region);for(let o of a)r({name:o.dependsOnStack,region:o.dependsOnRegion});n.push(i)};for(let i of e)r(i);return n}detectCircularDependencies(){let e=new Set,t=new Set,n=(r,i)=>{let s=`${r}:${i}`;if(t.has(s))return!0;if(e.has(s))return!1;e.add(s),t.add(s);let a=this.getDependencies(r,i);for(let o of a)if(n(o.dependsOnStack,o.dependsOnRegion))return!0;return t.delete(s),!1};for(let r of this.dependencies)if(n(r.dependentStack,r.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var rh=new fi,ih=new hi,sh=new bi,ah=new Si;var ue=[{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 dt(e){return ue.find((t)=>t.code===e)}function ch(){return ue}function lh(e){let t=e.toLowerCase();return ue.filter((n)=>n.location.toLowerCase().includes(t))}function uh(e){return ue.filter((t)=>t.compliance.includes(e))}function dh(e){return ue.filter((t)=>t.pricing.tier===e)}function mh(e){return ue.some((t)=>t.code===e)}function ph(e){if(e.continent==="North America")return dt("us-east-1");if(e.continent==="Europe")return dt("eu-west-1");if(e.continent==="Asia")return dt("ap-southeast-1");return dt("us-east-1")}function gh(e){let t=[...ue];if(e.compliance)t=t.filter((n)=>e.compliance.every((r)=>n.compliance.includes(r)));if(e.requiredServices)t=t.filter((n)=>e.requiredServices.every((r)=>n.services[r]));if(e.pricingSensitive)t.sort((n,r)=>n.pricing.multiplier-r.pricing.multiplier);return t.slice(0,5)}function yh(e){let t=dt(e);if(!t)throw Error(`Invalid region: ${e}`);let n=[];for(let r of ue){if(r.code===e)continue;let i=vc(t,r),s=Tc(t,r);n.push({primary:t,secondary:r,distance:i,sameContinent:s})}return n.sort((r,i)=>{if(r.sameContinent!==i.sameContinent)return r.sameContinent?1:-1;return r.distance-i.distance}),n.slice(0,3)}function vc(e,t){let n={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},r=mt(e.location),i=mt(t.location);return Math.abs((n[r]||0)-(n[i]||0))}function Tc(e,t){return mt(e.location)===mt(t.location)}function mt(e){if(e.includes("USA")||e.includes("Canada"))return"North America";if(e.includes("Europe")||e.includes("Ireland")||e.includes("Germany"))return"Europe";if(e.includes("Asia")||e.includes("Singapore")||e.includes("Japan"))return"Asia";if(e.includes("Brazil"))return"South America";if(e.includes("Australia"))return"Oceania";return"Unknown"}function Rc(e){return`${e.name} (${e.code})`}function fh(e){return e.map((t)=>Rc(t)).join(`
2752
+ `)}function hh(){let e={total:ue.length,byContinent:{},byPricingTier:{}};for(let t of ue){let n=mt(t.location);e.byContinent[n]=(e.byContinent[n]||0)+1,e.byPricingTier[t.pricing.tier]=(e.byPricingTier[t.pricing.tier]||0)+1}return e}class Ai{accounts=new Map;crossAccountRoles=[];accountMappings=[];registerAccount(e){this.accounts.set(e.id,e)}getAccount(e){return this.accounts.get(e)}getAccountByAlias(e){return Array.from(this.accounts.values()).find((t)=>t.alias===e)}listAccounts(){return Array.from(this.accounts.values())}getAccountsByRole(e){return Array.from(this.accounts.values()).filter((t)=>t.role===e)}createCrossAccountRole(e,t,n,r,i){let s={roleArn:`arn:aws:iam::${t}:role/${n}`,roleName:n,sourceAccountId:e,targetAccountId:t,permissions:r,externalId:i?.externalId,sessionDuration:i?.sessionDuration||3600};return this.crossAccountRoles.push(s),s}getAssumeRolePolicyDocument(e,t){let n={Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e}:root`},Action:"sts:AssumeRole"}]};if(t)n.Statement[0].Condition={StringEquals:{"sts:ExternalId":t}};return n}generateCrossAccountPolicy(e){return{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e,Resource:"*"}]}}mapEnvironmentToAccount(e,t,n){this.accountMappings.push({environment:e,accountId:t,region:n})}getAccountForEnvironment(e){return this.accountMappings.find((t)=>t.environment===e)}async assumeRole(e,t,n){return console.log(`Assuming role: ${e} with session: ${t}`),{accessKeyId:"AKIAIOSFODNN7EXAMPLE",secretAccessKey:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",sessionToken:"token",expiration:new Date(Date.now()+3600000)}}async getCredentialsForAccount(e){let t=this.accounts.get(e);if(!t)throw Error(`Account not found: ${e}`);if(t.assumeRoleArn){let n=await this.assumeRole(t.assumeRoleArn,`ts-cloud-${Date.now()}`);return{accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,sessionToken:n.sessionToken}}throw Error("No credentials available for account")}listCrossAccountRoles(){return[...this.crossAccountRoles]}getCrossAccountRolesForAccount(e){return this.crossAccountRoles.filter((t)=>t.sourceAccountId===e||t.targetAccountId===e)}async validateAccountAccess(e){try{let t=await this.getCredentialsForAccount(e);return console.log(`Validating access to account: ${e}`),!0}catch{return!1}}async getConsolidatedBilling(){let e={};for(let n of this.accounts.values())e[n.id]=Math.random()*1000;return{totalCost:Object.values(e).reduce((n,r)=>n+r,0),byAccount:e}}clear(){this.accounts.clear(),this.crossAccountRoles=[],this.accountMappings=[]}}class Ci{organizationId;organizationalUnits=new Map;getOrganizationId(){return this.organizationId}setOrganizationId(e){this.organizationId=e}createOrganizationalUnit(e,t){let n={id:`ou-${Date.now()}`,name:e,parentId:t,accounts:[]};return this.organizationalUnits.set(n.id,n),n}getOrganizationalUnit(e){return this.organizationalUnits.get(e)}listOrganizationalUnits(){return Array.from(this.organizationalUnits.values())}addAccountToOU(e,t){let n=this.organizationalUnits.get(e);if(!n)throw Error(`Organizational unit not found: ${e}`);if(!n.accounts.includes(t))n.accounts.push(t)}removeAccountFromOU(e,t){let n=this.organizationalUnits.get(e);if(!n)throw Error(`Organizational unit not found: ${e}`);n.accounts=n.accounts.filter((r)=>r!==t)}getAccountsInOU(e){let t=this.organizationalUnits.get(e);if(!t)return[];return[...t.accounts]}applyServiceControlPolicy(e,t){return{id:`scp-${Date.now()}`,name:"Custom SCP",targetId:e,policyDocument:t}}clear(){this.organizationId=void 0,this.organizationalUnits.clear()}}var Th=new Ai,Rh=new Ci;var Pc={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"}]}},Eh={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"]}}}]}}},wh={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 Ih(e){return Pc[e]}function Dh(e,t){return{Type:"AWS::IAM::Role",Properties:{RoleName:e.roleName,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e.sourceAccountId}:root`},Action:"sts:AssumeRole",...e.externalId&&{Condition:{StringEquals:{"sts:ExternalId":e.externalId}}}}]},Policies:[{PolicyName:`${e.roleName}Policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e.permissions,Resource:"*"}]}}],...t&&{ManagedPolicyArns:t},MaxSessionDuration:e.sessionDuration||3600,Tags:[{Key:"ManagedBy",Value:"TS-Cloud"},{Key:"SourceAccount",Value:e.sourceAccountId}]}}}function Nh(e){let t=[],n=[],r=e.accounts.filter((c)=>c.role==="management");if(r.length===0)t.push("No management account defined");if(r.length>1)t.push("Multiple management accounts defined");let i=e.accounts.map((c)=>c.email),s=i.filter((c,l)=>i.indexOf(c)!==l);if(s.length>0)t.push(`Duplicate email addresses: ${s.join(", ")}`);let a=e.accounts.map((c)=>c.alias),o=a.filter((c,l)=>a.indexOf(c)!==l);if(o.length>0)t.push(`Duplicate aliases: ${o.join(", ")}`);if(!e.accounts.some((c)=>c.role==="security"))n.push("No dedicated security account - consider adding one for audit logs");if(e.accounts.length<3)n.push("Less than 3 accounts - consider separating environments");if(!e.accounts.some((c)=>c.role==="production"))n.push("No production account defined");return{valid:t.length===0,errors:t,warnings:n}}function xh(e){let t=[];if(t.push(`${e.name}`),t.push("─".repeat(e.name.length)),t.push(e.description),t.push(""),e.organizationalUnits){t.push("Organizational Units:");for(let n of e.organizationalUnits){let r=n.parent?" └─ ":" ";t.push(`${r}${n.name}`)}t.push("")}t.push("Accounts:");for(let n of e.accounts)t.push(` ${n.alias.padEnd(20)} ${n.role.padEnd(15)} ${n.email}`),t.push(` ${"".padEnd(20)} ${n.description}`),t.push("");return t.join(`
2753
2753
  `)}function $h(e={}){let{workflowName:t="Deploy",trigger:n="push",branches:r=["main"],environments:i=["production"],awsRegion:s="us-east-1",awsRole:a,bunVersion:o="latest",deployCommand:c="bun run cloud deploy",testCommand:l="bun test",buildCommand:u="bun run build"}=e,m=!!a;return`name: ${t}
2754
2754
 
2755
2755
  on:
@@ -3584,7 +3584,7 @@ workflows:
3584
3584
  requires:
3585
3585
  - test
3586
3586
  ${i}
3587
- `}class yn{backupPlans=new Map;backupVaults=new Map;restoreJobs=new Map;continuousBackups=new Map;planCounter=0;restoreCounter=0;continuousBackupCounter=0;createVault(e){this.backupVaults.set(e.name,e)}getVault(e){return this.backupVaults.get(e)}createBackupPlan(e){let t=`backup-plan-${Date.now()}-${this.planCounter++}`,n={id:t,...e};return this.backupPlans.set(t,n),n}getBackupPlan(e){return this.backupPlans.get(e)}listBackupPlans(){return Array.from(this.backupPlans.values())}createRDSBackupPlan(e){let{dbInstanceArn:t,schedule:n="0 2 * * *",retentionDays:r=7,vaultName:i="default-vault"}=e;return this.createBackupPlan({name:"RDS Daily Backup",schedule:n,retentionDays:r,vaultName:i,resources:[{resourceArn:t,resourceType:"rds",region:"us-east-1"}],lifecycle:{moveTocoldStorageAfterDays:30,deleteAfterDays:r}})}createDynamoDBBackupPlan(e){let{tableArn:t,schedule:n="0 3 * * *",retentionDays:r=35,crossRegionCopy:i}=e;return this.createBackupPlan({name:"DynamoDB Daily Backup",schedule:n,retentionDays:r,vaultName:"dynamodb-vault",resources:[{resourceArn:t,resourceType:"dynamodb",region:"us-east-1"}],lifecycle:{deleteAfterDays:r},tags:i?{CrossRegionCopy:i.join(",")}:void 0})}createEFSBackupPlan(e){let{fileSystemArn:t,schedule:n="0 1 * * *",retentionDays:r=30}=e;return this.createBackupPlan({name:"EFS Daily Backup",schedule:n,retentionDays:r,vaultName:"efs-vault",resources:[{resourceArn:t,resourceType:"efs",region:"us-east-1"}],lifecycle:{deleteAfterDays:r}})}enableContinuousBackup(e,t=35){let n=`continuous-backup-${Date.now()}-${this.continuousBackupCounter++}`,r={id:n,resourceId:e,enabled:!0,retentionDays:t};return this.continuousBackups.set(n,r),r}getContinuousBackup(e){return this.continuousBackups.get(e)}enablePointInTimeRecovery(e,t){return{enabled:!0,earliestRestorableTime:new Date(Date.now()-604800000),latestRestorableTime:new Date}}async restoreFromBackup(e){let{backupId:t,resourceType:n,targetRegion:r}=e,i={id:`restore-${Date.now()}-${this.restoreCounter++}`,backupId:t,resourceType:n,status:"pending",startTime:new Date,targetRegion:r};return this.restoreJobs.set(i.id,i),setTimeout(()=>{i.status="running"},100),setTimeout(()=>{i.status="completed",i.endTime=new Date},1000),i}async restoreToPointInTime(e){let{sourceResourceArn:t,targetResourceName:n,restoreTime:r,resourceType:i}=e,s={id:`pitr-${Date.now()}-${this.restoreCounter++}`,backupId:`pitr-${r.getTime()}`,resourceType:i,status:"pending",startTime:new Date};return this.restoreJobs.set(s.id,s),console.log(`Restoring ${i} from ${t} to ${n} at ${r.toISOString()}`),setTimeout(()=>{s.status="completed",s.endTime=new Date},2000),s}getRestoreJob(e){return this.restoreJobs.get(e)}listRestoreJobs(){return Array.from(this.restoreJobs.values())}setupCrossRegionReplication(e){let{sourceVault:t,sourceRegion:n,targetRegions:r}=e;console.log("Setting up cross-region replication:"),console.log(` Source: ${t} in ${n}`),console.log(` Targets: ${r.join(", ")}`)}generateBackupVaultCF(e){return{Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:e.name,...e.encryptionKeyArn&&{EncryptionKeyArn:e.encryptionKeyArn},...e.accessPolicy&&{AccessPolicy:e.accessPolicy}}}}generateBackupPlanCF(e){return{Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:e.name,BackupPlanRule:[{RuleName:"DailyBackup",TargetBackupVault:e.vaultName,ScheduleExpression:`cron(${e.schedule})`,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:e.lifecycle?{...e.lifecycle.moveTocoldStorageAfterDays&&{MoveToColdStorageAfterDays:e.lifecycle.moveTocoldStorageAfterDays},...e.lifecycle.deleteAfterDays&&{DeleteAfterDays:e.lifecycle.deleteAfterDays}}:void 0}]},...e.tags&&{BackupPlanTags:e.tags}}}}generateBackupSelectionCF(e){return{Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:{Ref:`BackupPlan${e.id}`},BackupSelection:{SelectionName:`${e.name}Selection`,IamRoleArn:"arn:aws:iam::123456789012:role/service-role/AWSBackupDefaultServiceRole",Resources:e.resources.map((t)=>t.resourceArn)}}}}clear(){this.backupPlans.clear(),this.backupVaults.clear(),this.restoreJobs.clear(),this.continuousBackups.clear(),this.planCounter=0,this.restoreCounter=0,this.continuousBackupCounter=0}}var Ec=new yn;class fn{drPlans=new Map;failoverTests=new Map;planCounter=0;testCounter=0;createDRPlan(e){let t=`dr-plan-${Date.now()}-${this.planCounter++}`,n={id:t,...e};return this.drPlans.set(t,n),n}createRDSDRPlan(e){let{primaryDbArn:t,secondaryDbArn:n,primaryRegion:r,secondaryRegion:i,rto:s=60,rpo:a=5}=e;return this.createDRPlan({name:"RDS Multi-Region DR",primaryRegion:r,secondaryRegion:i,rto:s,rpo:a,resources:[{resourceId:"primary-db",resourceType:"rds",primaryArn:t,secondaryArn:n,replicationEnabled:!0}],runbook:this.generateRDSRunbook(r,i),testSchedule:"0 0 1 * *"})}createDynamoDBDRPlan(e){let{tableArn:t,regions:n,rto:r=15,rpo:i=1}=e;return this.createDRPlan({name:"DynamoDB Global Tables DR",primaryRegion:n[0],secondaryRegion:n[1],rto:r,rpo:i,resources:[{resourceId:"dynamodb-table",resourceType:"dynamodb",primaryArn:t,replicationEnabled:!0}],runbook:this.generateDynamoDBRunbook(n)})}generateRDSRunbook(e,t){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 "+e,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 "+t,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(e){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(e,t=!1){let n=this.drPlans.get(e);if(!n)throw Error(`DR plan not found: ${e}`);let r=Date.now(),i=0;console.log(`${t?"[DRY RUN] ":""}Executing failover for plan: ${n.name}`),console.log(`Primary: ${n.primaryRegion} -> Secondary: ${n.secondaryRegion}`),console.log(`RTO: ${n.rto} minutes, RPO: ${n.rpo} minutes`),console.log("");for(let a of n.runbook.steps){if(console.log(`Step ${a.order}: ${a.name}`),console.log(` ${a.description}`),console.log(` Action: ${a.action}`),console.log(` Estimated: ${a.estimatedDuration} minutes`),t)console.log(" [SKIPPED - DRY RUN]");else if(a.automatable)console.log(" [AUTOMATED]");else console.log(" [MANUAL - WAITING]");i++,console.log("")}return{success:!0,duration:(Date.now()-r)/1000/60,completedSteps:i}}scheduleFailoverTest(e,t){let n={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:e,status:"scheduled",startTime:t};return this.failoverTests.set(n.id,n),n}async runFailoverTest(e){let t=this.drPlans.get(e);if(!t)throw Error(`DR plan not found: ${e}`);let n={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:e,status:"running",startTime:new Date,results:[]};this.failoverTests.set(n.id,n),console.log(`Running failover test for plan: ${t.name}`),console.log("This is a non-destructive test using test resources"),console.log("");for(let r of t.runbook.steps){let i=Date.now();console.log(`Testing step ${r.order}: ${r.name}`);let s={step:r.name,status:"success",duration:(Date.now()-i)/1000,message:`Successfully validated step ${r.order}`};n.results.push(s)}return n.status="completed",n.endTime=new Date,n}getDRPlan(e){return this.drPlans.get(e)}listDRPlans(){return Array.from(this.drPlans.values())}getFailoverTest(e){return this.failoverTests.get(e)}listFailoverTests(){return Array.from(this.failoverTests.values())}validateDRPlan(e){let t=[],n=[];if(e.rto<e.rpo)n.push("RTO cannot be less than RPO");if(e.rto>240)t.push("RTO exceeds 4 hours - consider improving recovery time");if(e.rpo>60)t.push("RPO exceeds 1 hour - consider more frequent backups");if(e.resources.length===0)n.push("No resources defined in DR plan");for(let s of e.resources){if(!s.replicationEnabled)t.push(`Resource ${s.resourceId} does not have replication enabled`);if(!s.secondaryArn&&s.resourceType!=="dynamodb")t.push(`Resource ${s.resourceId} does not have secondary resource defined`)}if(e.runbook.steps.length===0)n.push("No recovery steps defined in runbook");let r=e.runbook.steps.reduce((s,a)=>s+a.estimatedDuration,0);if(r>e.rto)t.push(`Estimated recovery duration (${r}m) exceeds RTO (${e.rto}m)`);let i=e.runbook.steps.filter((s)=>!s.automatable);if(i.length>0)t.push(`${i.length} manual steps in runbook - consider automation`);return{valid:n.length===0,warnings:t,errors:n}}clear(){this.drPlans.clear(),this.failoverTests.clear(),this.planCounter=0,this.testCounter=0}}var wc=new fn;class hn{configRules=new Map;configRecorders=new Map;deliveryChannels=new Map;ruleCounter=0;createConfigRecorder(e){return this.configRecorders.set(e.name,e),e}createDeliveryChannel(e){return this.deliveryChannels.set(e.name,e),e}createConfigRule(e){let t=`config-rule-${Date.now()}-${this.ruleCounter++}`,n={id:t,...e};return this.configRules.set(t,n),n}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(e=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:e},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(e){return this.createConfigRule({name:e.name,description:e.description,source:"CUSTOM_LAMBDA",lambdaFunctionArn:e.lambdaFunctionArn,scope:e.resourceTypes?{complianceResourceTypes:e.resourceTypes}:void 0,maxExecutionFrequency:e.maxExecutionFrequency,inputParameters:e.inputParameters})}createCompliancePreset(e){let t=[];switch(e){case"hipaa":t.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createRdsBackupRule(7),this.createVpcFlowLogsRule());break;case"pci-dss":t.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createIamMfaRule(),this.createRootAccountMfaRule(),this.createVpcFlowLogsRule());break;case"sox":t.push(this.createS3VersioningRule(),this.createCloudTrailEnabledRule(),this.createRdsBackupRule(30),this.createIamPasswordPolicyRule());break;case"gdpr":t.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createRdsSnapshotEncryptionRule());break;case"basic":t.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamMfaRule(),this.createRootAccountMfaRule());break}return t}getConfigRule(e){return this.configRules.get(e)}listConfigRules(){return Array.from(this.configRules.values())}getConfigRecorder(e){return this.configRecorders.get(e)}listConfigRecorders(){return Array.from(this.configRecorders.values())}getDeliveryChannel(e){return this.deliveryChannels.get(e)}listDeliveryChannels(){return Array.from(this.deliveryChannels.values())}generateConfigRuleCF(e){let t={Type:"AWS::Config::ConfigRule",Properties:{ConfigRuleName:e.name,Description:e.description,Source:{Owner:e.source==="AWS_MANAGED"?"AWS":"CUSTOM_LAMBDA"}}};if(e.source==="AWS_MANAGED"&&e.identifier)t.Properties.Source.SourceIdentifier=e.identifier;if(e.source==="CUSTOM_LAMBDA"&&e.lambdaFunctionArn)t.Properties.Source.SourceIdentifier=e.lambdaFunctionArn,t.Properties.Source.SourceDetails=[{EventSource:"aws.config",MessageType:"ConfigurationItemChangeNotification"}];if(e.inputParameters)t.Properties.InputParameters=JSON.stringify(e.inputParameters);if(e.scope){if(t.Properties.Scope={},e.scope.complianceResourceTypes)t.Properties.Scope.ComplianceResourceTypes=e.scope.complianceResourceTypes;if(e.scope.tagKey)t.Properties.Scope.TagKey=e.scope.tagKey;if(e.scope.tagValue)t.Properties.Scope.TagValue=e.scope.tagValue}if(e.maxExecutionFrequency)t.Properties.MaximumExecutionFrequency=e.maxExecutionFrequency;return t}generateConfigRecorderCF(e){return{Type:"AWS::Config::ConfigurationRecorder",Properties:{Name:e.name,RoleArn:e.roleArn,RecordingGroup:e.recordingGroup||{AllSupported:!0,IncludeGlobalResourceTypes:!0}}}}generateDeliveryChannelCF(e){return{Type:"AWS::Config::DeliveryChannel",Properties:{Name:e.name,S3BucketName:e.s3BucketName,...e.s3KeyPrefix&&{S3KeyPrefix:e.s3KeyPrefix},...e.snsTopicArn&&{SnsTopicARN:e.snsTopicArn},...e.configSnapshotDeliveryProperties&&{ConfigSnapshotDeliveryProperties:e.configSnapshotDeliveryProperties}}}}clear(){this.configRules.clear(),this.configRecorders.clear(),this.deliveryChannels.clear(),this.ruleCounter=0}}var Ic=new hn;class bn{trails=new Map;trailCounter=0;createTrail(e){let t=`trail-${Date.now()}-${this.trailCounter++}`,n={id:t,...e};return this.trails.set(t,n),n}createOrganizationTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,s3KeyPrefix:"organization-trail",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:e.kmsKeyId,cloudWatchLogsLogGroupArn:e.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:e.cloudWatchLogsRoleArn})}createSecurityAuditTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,s3KeyPrefix:"security-audit",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:e.kmsKeyId,cloudWatchLogsLogGroupArn:e.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:e.cloudWatchLogsRoleArn,eventSelectors:[{readWriteType:"All",includeManagementEvents:!0,excludeManagementEventSources:[]}],insightSelectors:[{insightType:"ApiCallRateInsight"},{insightType:"ApiErrorRateInsight"}]})}createDataEventsTrail(e){let t=[];if(e.s3DataBuckets&&e.s3DataBuckets.length>0)t.push({type:"AWS::S3::Object",values:e.s3DataBuckets.map((n)=>`arn:aws:s3:::${n}/*`)});if(e.lambdaFunctions&&e.lambdaFunctions.length>0)t.push({type:"AWS::Lambda::Function",values:e.lambdaFunctions});return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,s3KeyPrefix:"data-events",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"All",includeManagementEvents:!1,dataResources:t}]})}createAdvancedTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,advancedEventSelectors:e.selectors})}createReadOnlyTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"ReadOnly",includeManagementEvents:!0}]})}createWriteOnlyTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"WriteOnly",includeManagementEvents:!0}]})}getTrail(e){return this.trails.get(e)}listTrails(){return Array.from(this.trails.values())}generateTrailCF(e){let t={Type:"AWS::CloudTrail::Trail",Properties:{TrailName:e.name,S3BucketName:e.s3BucketName,IsLogging:!0,IncludeGlobalServiceEvents:e.includeGlobalServiceEvents??!0,IsMultiRegionTrail:e.isMultiRegionTrail??!0,EnableLogFileValidation:e.enableLogFileValidation??!0}};if(e.s3KeyPrefix)t.Properties.S3KeyPrefix=e.s3KeyPrefix;if(e.cloudWatchLogsLogGroupArn)t.Properties.CloudWatchLogsLogGroupArn=e.cloudWatchLogsLogGroupArn;if(e.cloudWatchLogsRoleArn)t.Properties.CloudWatchLogsRoleArn=e.cloudWatchLogsRoleArn;if(e.snsTopicName)t.Properties.SnsTopicName=e.snsTopicName;if(e.kmsKeyId)t.Properties.KMSKeyId=e.kmsKeyId;if(e.eventSelectors)t.Properties.EventSelectors=e.eventSelectors.map((n)=>({ReadWriteType:n.readWriteType,IncludeManagementEvents:n.includeManagementEvents??!0,...n.dataResources&&{DataResources:n.dataResources.map((r)=>({Type:r.type,Values:r.values}))},...n.excludeManagementEventSources&&{ExcludeManagementEventSources:n.excludeManagementEventSources}}));if(e.insightSelectors)t.Properties.InsightSelectors=e.insightSelectors.map((n)=>({InsightType:n.insightType}));if(e.advancedEventSelectors)t.Properties.AdvancedEventSelectors=e.advancedEventSelectors.map((n)=>({Name:n.name,FieldSelectors:n.fieldSelectors.map((r)=>({Field:r.field,...r.equals&&{Equals:r.equals},...r.startsWith&&{StartsWith:r.startsWith},...r.endsWith&&{EndsWith:r.endsWith},...r.notEquals&&{NotEquals:r.notEquals},...r.notStartsWith&&{NotStartsWith:r.notStartsWith},...r.notEndsWith&&{NotEndsWith:r.notEndsWith}}))}));return t}generateBucketPolicy(e,t){return{Version:"2012-10-17",Statement:[{Sid:"AWSCloudTrailAclCheck",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:GetBucketAcl",Resource:`arn:aws:s3:::${e}`},{Sid:"AWSCloudTrailWrite",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:PutObject",Resource:t.map((n)=>`arn:aws:s3:::${e}/AWSLogs/${n}/*`),Condition:{StringEquals:{"s3:x-amz-acl":"bucket-owner-full-control"}}}]}}clear(){this.trails.clear(),this.trailCounter=0}}var Dc=new bn;class Sn{detectors=new Map;threatIntelSets=new Map;ipSets=new Map;filters=new Map;detectorCounter=0;threatIntelCounter=0;ipSetCounter=0;filterCounter=0;createDetector(e){let t=`detector-${Date.now()}-${this.detectorCounter++}`,n={id:t,...e};return this.detectors.set(t,n),n}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(e){let t=`threat-intel-${Date.now()}-${this.threatIntelCounter++}`,n={id:t,...e};return this.threatIntelSets.set(t,n),n}createIPSet(e){let t=`ip-set-${Date.now()}-${this.ipSetCounter++}`,n={id:t,...e};return this.ipSets.set(t,n),n}createFindingFilter(e){let t=`filter-${Date.now()}-${this.filterCounter++}`,n={id:t,...e};return this.filters.set(t,n),n}createLowSeverityArchiveFilter(e){return this.createFindingFilter({detectorId:e,name:"archive-low-severity",description:"Automatically archive low severity findings",action:"ARCHIVE",rank:1,findingCriteria:{criterion:{severity:{lt:4}}}})}createFindingTypeFilter(e,t,n){return this.createFindingFilter({detectorId:e,name:`filter-finding-types-${n.toLowerCase()}`,description:`${n==="ARCHIVE"?"Archive":"Keep"} specific finding types`,action:n,rank:2,findingCriteria:{criterion:{type:{eq:t}}}})}createTrustedIPFilter(e,t){return this.createFindingFilter({detectorId:e,name:"trusted-ip-addresses",description:"Archive findings from trusted IP addresses",action:"ARCHIVE",rank:3,findingCriteria:{criterion:{"resource.instanceDetails.networkInterfaces.privateIpAddress":{eq:t}}}})}getDetector(e){return this.detectors.get(e)}listDetectors(){return Array.from(this.detectors.values())}getThreatIntelSet(e){return this.threatIntelSets.get(e)}listThreatIntelSets(){return Array.from(this.threatIntelSets.values())}getIPSet(e){return this.ipSets.get(e)}listIPSets(){return Array.from(this.ipSets.values())}getFindingFilter(e){return this.filters.get(e)}listFindingFilters(){return Array.from(this.filters.values())}generateDetectorCF(e){let t={Type:"AWS::GuardDuty::Detector",Properties:{Enable:e.enable}};if(e.findingPublishingFrequency)t.Properties.FindingPublishingFrequency=e.findingPublishingFrequency;if(e.dataSources){if(t.Properties.DataSources={},e.dataSources.s3Logs)t.Properties.DataSources.S3Logs={Enable:e.dataSources.s3Logs.enable};if(e.dataSources.kubernetes)t.Properties.DataSources.Kubernetes={AuditLogs:{Enable:e.dataSources.kubernetes.auditLogs.enable}};if(e.dataSources.malwareProtection)t.Properties.DataSources.MalwareProtection={ScanEc2InstanceWithFindings:{EbsVolumes:{Enable:e.dataSources.malwareProtection.scanEc2InstanceWithFindings.ebsVolumes.enable}}}}if(e.features)t.Properties.Features=e.features.map((n)=>({Name:n.name,Status:n.status,...n.additionalConfiguration&&{AdditionalConfiguration:n.additionalConfiguration}}));return t}generateThreatIntelSetCF(e){return{Type:"AWS::GuardDuty::ThreatIntelSet",Properties:{DetectorId:e.detectorId,Name:e.name,Format:e.format,Location:e.location,Activate:e.activate}}}generateIPSetCF(e){return{Type:"AWS::GuardDuty::IPSet",Properties:{DetectorId:e.detectorId,Name:e.name,Format:e.format,Location:e.location,Activate:e.activate}}}generateFilterCF(e){return{Type:"AWS::GuardDuty::Filter",Properties:{DetectorId:e.detectorId,Name:e.name,Description:e.description,Action:e.action,Rank:e.rank,FindingCriteria:{Criterion:e.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 Nc=new Sn;class Ne{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(e){let t=`hub-${Date.now()}-${this.hubCounter++}`,n={id:t,...e};return this.hubs.set(t,n),n}createComprehensiveHub(){return this.createHub({enable:!0,controlFindingGenerator:"SECURITY_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...Ne.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...Ne.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...Ne.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...Ne.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(e){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:e.map((t)=>({value:t,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(e,t){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:`Suppress False Positives - ${e}`,description:`Automatically suppress known false positives from ${e}`,actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"SUPPRESSED"},note:{text:"Known false positive - automatically suppressed",updatedBy:"SecurityHub Automation"}}}],criteria:{productName:[{value:e,comparison:"EQUALS"}],title:t.map((n)=>({value:n,comparison:"PREFIX"}))},ruleStatus:"ENABLED",ruleOrder:10}}getHub(e){return this.hubs.get(e)}listHubs(){return Array.from(this.hubs.values())}generateHubCF(e){let t={Type:"AWS::SecurityHub::Hub",Properties:{}};if(e.controlFindingGenerator)t.Properties.ControlFindingGenerator=e.controlFindingGenerator;if(e.enableDefaultStandards!==void 0)t.Properties.EnableDefaultStandards=e.enableDefaultStandards;return t}generateStandardCF(e){let t={Type:"AWS::SecurityHub::Standard",Properties:{StandardsArn:e.arn}};if(e.disabledControls&&e.disabledControls.length>0)t.Properties.DisabledStandardsControls=e.disabledControls.map((n)=>({StandardsControlArn:n,Reason:"Disabled by configuration"}));return t}generateAutomationRuleCF(e){return{Type:"AWS::SecurityHub::AutomationRule",Properties:{RuleName:e.ruleName,Description:e.description,Actions:e.actions.map((t)=>({Type:t.type,FindingFieldsUpdate:t.findingFieldsUpdate})),Criteria:e.criteria,RuleStatus:e.ruleStatus,RuleOrder:e.ruleOrder}}}clear(){this.hubs.clear(),this.hubCounter=0,this.ruleCounter=0}}var xc=new Ne;class An{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;createDeployment(e){let t=`bg-deployment-${Date.now()}-${this.deploymentCounter++}`,n={id:t,...e};return this.deployments.set(t,n),n}createALBDeployment(e){return this.createDeployment({name:e.name,blueEnvironment:{name:"blue",targetGroupArn:e.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:e.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:e.listenerArn,switchoverTimeSeconds:0},autoPromote:e.autoPromote,healthCheckConfig:e.healthCheckConfig})}createRoute53Deployment(e){return this.createDeployment({name:e.name,blueEnvironment:{name:"blue",targetGroupArn:e.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:e.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"route53",hostedZoneId:e.hostedZoneId,switchoverTimeSeconds:e.switchoverTimeSeconds||60}})}createECSDeployment(e){return this.createDeployment({name:e.name,blueEnvironment:{name:"blue",targetGroupArn:e.blueTargetGroupArn,taskDefinitionArn:e.blueTaskDefinitionArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:e.greenTargetGroupArn,taskDefinitionArn:e.greenTaskDefinitionArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:e.listenerArn},autoRollback:e.autoRollback??!0})}async executeDeployment(e,t=!1){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!1,errors:[]};console.log(`${t?"[DRY RUN] ":""}Starting blue/green deployment: ${n.name}`),console.log(` Active environment: ${n.activeEnvironment}`),console.log(` Routing type: ${n.routingConfig.type}`);let i=n.activeEnvironment==="blue"?"green":"blue";if(console.log(` Switching to: ${i}`),console.log(`\\n1. Deploying to ${i} environment`),!t)await new Promise((s)=>setTimeout(s,100));if(console.log(`\\n2. Running health checks on ${i} environment`),n.healthCheckConfig){let s=await this.runHealthChecks(n,i,t);if(r.healthChecksPassed=s,!s){if(r.errors?.push("Health checks failed"),r.endTime=new Date,n.autoRollback)console.log(" Auto-rollback enabled - keeping current environment active"),r.rolledBackAt=new Date;return this.recordDeployment(e,r),r}}else r.healthChecksPassed=!0;if(console.log(`\\n3. Switching traffic to ${i} environment`),!t)n.activeEnvironment=i,r.switchedAt=new Date;if(console.log(`\\n4. Monitoring ${i} environment`),!t)await new Promise((s)=>setTimeout(s,100));return r.success=!0,r.endTime=new Date,console.log("\\n✓ Deployment completed successfully"),this.recordDeployment(e,r),r}async rollback(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);let n={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!0,errors:[]};console.log(`Rolling back deployment: ${t.name}`);let r=t.activeEnvironment==="blue"?"green":"blue";return t.activeEnvironment=r,n.success=!0,n.rolledBackAt=new Date,n.endTime=new Date,console.log(` Switched back to: ${r}`),this.recordDeployment(e,n),n}async runHealthChecks(e,t,n){let r=e.healthCheckConfig;if(console.log(` Health check path: ${r.path||"/"}`),console.log(` Healthy threshold: ${r.healthyThreshold}`),console.log(` Interval: ${r.interval}s`),n)return console.log(" [SKIPPED - DRY RUN]"),!0;let i=0,s=r.healthyThreshold+2;for(let a=0;a<s;a++)if(await new Promise((c)=>setTimeout(c,50)),Math.random()>0.1){if(i++,console.log(` Check ${a+1}: ✓ Healthy (${i}/${r.healthyThreshold})`),i>=r.healthyThreshold)return!0}else i=0,console.log(` Check ${a+1}: ✗ Unhealthy`);return!1}recordDeployment(e,t){if(!this.deploymentHistory.has(e))this.deploymentHistory.set(e,[]);this.deploymentHistory.get(e).push(t)}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(e){return this.deploymentHistory.get(e)||[]}generateALBListenerCF(e){let t=e.activeEnvironment==="blue"?e.blueEnvironment:e.greenEnvironment;return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:e.routingConfig.listenerArn,Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",TargetGroupArn:t.targetGroupArn}]}}}generateRoute53RecordSetCF(e,t){return[{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.routingConfig.hostedZoneId,Name:t,Type:"A",SetIdentifier:"blue",Weight:e.activeEnvironment==="blue"?100:0,AliasTarget:{HostedZoneId:e.routingConfig.hostedZoneId,DNSName:e.blueEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}},{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.routingConfig.hostedZoneId,Name:t,Type:"A",SetIdentifier:"green",Weight:e.activeEnvironment==="green"?100:0,AliasTarget:{HostedZoneId:e.routingConfig.hostedZoneId,DNSName:e.greenEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}}]}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var kc=new An;class mt{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(e){let t=`canary-${Date.now()}-${this.deploymentCounter++}`,n={id:t,...e};return this.deployments.set(t,n),n}createLambdaCanaryDeployment(e){let t=e.strategy||"BALANCED",n=mt.Strategies[t].map((r)=>({...r,alarmThresholds:{errorRate:e.errorRateThreshold||1,latencyP99:e.latencyThreshold||1000}}));return this.createDeployment({name:e.name,baselineVersion:{version:"baseline",functionVersionArn:e.baselineVersionArn,weight:100},canaryVersion:{version:"canary",functionVersionArn:e.canaryVersionArn,weight:0},stages:n,currentStage:0,status:"pending",autoPromote:e.autoPromote??!0,autoRollback:!0})}createECSCanaryDeployment(e){let t=e.strategy||"CONSERVATIVE",n=mt.Strategies[t];return this.createDeployment({name:e.name,baselineVersion:{version:"baseline",taskDefinitionArn:e.baselineTaskDefinitionArn,targetGroupArn:e.baselineTargetGroupArn,weight:100},canaryVersion:{version:"canary",taskDefinitionArn:e.canaryTaskDefinitionArn,targetGroupArn:e.canaryTargetGroupArn,weight:0},stages:n,currentStage:0,status:"pending",autoRollback:!0})}async executeDeployment(e,t=!1){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,completedStages:0,rolledBack:!1};console.log(`${t?"[DRY RUN] ":""}Starting canary deployment: ${n.name}`),console.log(` Strategy: ${n.stages.length} stages`),console.log(` Auto-promote: ${n.autoPromote}`),console.log(` Auto-rollback: ${n.autoRollback}`),console.log(""),n.status="in_progress";for(let i=0;i<n.stages.length;i++){let s=n.stages[i];if(n.currentStage=i,console.log(`Stage ${i+1}/${n.stages.length}: ${s.name}`),console.log(` Traffic: ${s.trafficPercentage}% canary, ${100-s.trafficPercentage}% baseline`),console.log(` Duration: ${s.durationMinutes} minutes`),!t)n.baselineVersion.weight=100-s.trafficPercentage,n.canaryVersion.weight=s.trafficPercentage;if(!await this.monitorStage(n,s,t)){if(console.log(" ✗ Stage failed - metrics exceeded thresholds"),n.autoRollback)console.log("\\n Rolling back deployment..."),await this.rollback(e,t),r.rolledBack=!0,r.reason="Metrics exceeded thresholds";return r.endTime=new Date,n.status="rolled_back",this.recordDeployment(e,r),r}console.log(" ✓ Stage completed successfully"),r.completedStages++,console.log("")}return n.status="completed",r.success=!0,r.endTime=new Date,console.log("✓ Canary deployment completed successfully"),this.recordDeployment(e,r),r}async monitorStage(e,t,n){if(console.log(" Monitoring metrics..."),n)return console.log(" [SKIPPED - DRY RUN]"),!0;await new Promise((i)=>setTimeout(i,100));let r={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)*t.trafficPercentage/100)};if(e.metrics=r,console.log(` Baseline: ${r.baselineErrorRate.toFixed(2)}% errors, ${r.baselineLatencyP99.toFixed(0)}ms P99`),console.log(` Canary: ${r.canaryErrorRate.toFixed(2)}% errors, ${r.canaryLatencyP99.toFixed(0)}ms P99`),t.alarmThresholds){let{errorRate:i,latencyP99:s}=t.alarmThresholds;if(i&&r.canaryErrorRate>i)return console.log(` ⚠ Error rate exceeded threshold: ${r.canaryErrorRate.toFixed(2)}% > ${i}%`),!1;if(s&&r.canaryLatencyP99>s)return console.log(` ⚠ Latency P99 exceeded threshold: ${r.canaryLatencyP99.toFixed(0)}ms > ${s}ms`),!1}return!0}async rollback(e,t=!1){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);if(console.log(`${t?"[DRY RUN] ":""}Rolling back canary deployment: ${n.name}`),!t)n.baselineVersion.weight=100,n.canaryVersion.weight=0,n.status="rolled_back";console.log(" Traffic restored to baseline: 100%")}promoteCanary(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);console.log(`Promoting canary to baseline: ${t.name}`);let n=t.baselineVersion;t.baselineVersion=t.canaryVersion,t.canaryVersion=n,t.baselineVersion.weight=100,t.canaryVersion.weight=0,t.status="completed",console.log(" Canary promoted successfully")}recordDeployment(e,t){if(!this.deploymentHistory.has(e))this.deploymentHistory.set(e,[]);this.deploymentHistory.get(e).push(t)}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(e){return this.deploymentHistory.get(e)||[]}generateLambdaAliasCF(e,t){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:{Ref:"LambdaFunction"},Name:t,FunctionVersion:e.canaryVersion.version,RoutingConfig:{AdditionalVersionWeights:[{FunctionVersion:e.baselineVersion.version,FunctionWeight:e.baselineVersion.weight/100}]}}}}generateALBListenerRuleCF(e){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:[{TargetGroupArn:e.baselineVersion.targetGroupArn,Weight:e.baselineVersion.weight},{TargetGroupArn:e.canaryVersion.targetGroupArn,Weight:e.canaryVersion.weight}],TargetGroupStickinessConfig:{Enabled:!1}}}]}}}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var Mc=new mt;class Cn{tests=new Map;testCounter=0;createTest(e){let t=`abtest-${Date.now()}-${this.testCounter++}`,n={id:t,...e};return this.tests.set(t,n),n}createSimpleABTest(e){let t=e.variantTrafficPercentage||50;return this.createTest({name:e.name,description:e.description,variants:[{id:"control",name:"Control",description:"Original version",trafficPercentage:100-t,targetGroupArn:e.controlTargetGroupArn,weight:100-t},{id:"variant-a",name:"Variant A",description:"Test version",trafficPercentage:t,targetGroupArn:e.variantTargetGroupArn,weight:t}],routingStrategy:{type:e.stickySession?"cookie":"random",cookieName:e.stickySession?"ab_variant":void 0,stickySession:e.stickySession??!1,sessionDuration:1440},startTime:new Date,status:"draft"})}createMultivariateTest(e){let t=e.variants.reduce((n,r)=>n+r.trafficPercentage,0);if(t!==100)throw Error(`Traffic percentages must sum to 100, got ${t}`);return this.createTest({name:e.name,description:e.description,variants:e.variants.map((n,r)=>({id:`variant-${r}`,name:n.name,description:n.description,trafficPercentage:n.trafficPercentage,targetGroupArn:n.targetGroupArn,weight:n.trafficPercentage})),routingStrategy:e.routingStrategy||{type:"random",stickySession:!1},startTime:new Date,status:"draft"})}createHeaderBasedTest(e){return this.createTest({name:e.name,description:`Route based on ${e.headerName} header`,variants:[{id:"control",name:"Control",trafficPercentage:50,targetGroupArn:e.controlTargetGroupArn,weight:50},{id:"variant-a",name:"Variant A",trafficPercentage:50,targetGroupArn:e.variantTargetGroupArn,weight:50}],routingStrategy:{type:"header",headerName:e.headerName,stickySession:!1},startTime:new Date,status:"draft"})}createGeoBasedTest(e){return this.createTest({name:e.name,description:"Route based on geographic location",variants:[{id:"control",name:"Control (Rest of World)",trafficPercentage:50,targetGroupArn:e.controlTargetGroupArn,weight:50},{id:"variant-a",name:`Variant A (${e.regions.join(", ")})`,trafficPercentage:50,targetGroupArn:e.variantTargetGroupArn,weight:50}],routingStrategy:{type:"geo",stickySession:!0,sessionDuration:1440},startTime:new Date,status:"draft"})}startTest(e){let t=this.tests.get(e);if(!t)throw Error(`Test not found: ${e}`);if(t.status!=="draft"&&t.status!=="paused")throw Error(`Cannot start test in ${t.status} status`);t.status="active",t.startTime=new Date,console.log(`Started A/B test: ${t.name}`),console.log(` Variants: ${t.variants.length}`),t.variants.forEach((n)=>{console.log(` - ${n.name}: ${n.trafficPercentage}%`)})}pauseTest(e){let t=this.tests.get(e);if(!t)throw Error(`Test not found: ${e}`);t.status="paused",console.log(`Paused A/B test: ${t.name}`)}updateTrafficSplit(e,t,n){let r=this.tests.get(e);if(!r)throw Error(`Test not found: ${e}`);let i=r.variants.find((a)=>a.id===t);if(!i)throw Error(`Variant not found: ${t}`);let s=i.trafficPercentage;i.trafficPercentage=n,i.weight=n,console.log(`Updated ${i.name} traffic: ${s}% → ${n}%`)}analyzeResults(e){let t=this.tests.get(e);if(!t)throw Error(`Test not found: ${e}`);if(!t.metrics)t.metrics=this.collectMetrics(t);let n=t.variants[0],r=0;for(let l of t.variants){let u=t.metrics.variants[l.id];if(u&&u.conversionRate>r)r=u.conversionRate,n=l}let i=t.metrics.variants.control||t.metrics.variants[t.variants[0].id],s=t.metrics.variants[n.id],a=(s.conversionRate-i.conversionRate)/i.conversionRate*100,o=100,c=s.requests>o&&i.requests>o&&Math.abs(a)>10;return{testId:e,winningVariant:n.name,confidence:c?95:75,improvement:a,statisticalSignificance:c,metrics:t.metrics,recommendation:this.generateRecommendation(a,c,n.name)}}declareWinner(e,t){let n=this.tests.get(e);if(!n)throw Error(`Test not found: ${e}`);let r=n.variants.find((i)=>i.id===t);if(!r)throw Error(`Variant not found: ${t}`);n.variants.forEach((i)=>{if(i.id===t)i.trafficPercentage=100,i.weight=100;else i.trafficPercentage=0,i.weight=0}),n.status="completed",n.endTime=new Date,n.winner=t,console.log(`Declared winner: ${r.name}`),console.log(` All traffic now routed to ${r.name}`)}collectMetrics(e){let t={},n=0;for(let r of e.variants){let i=Math.floor(Math.random()*1000)+500,s=Math.floor(i*(Math.random()*0.1+0.05)),a=s/i*100;t[r.id]={requests:i,conversions:s,conversionRate:a,averageLatency:150+Math.random()*100,errorRate:Math.random()*0.5,revenue:s*(Math.random()*50+100)},n+=i}return{variants:t,totalRequests:n,startTime:e.startTime,lastUpdated:new Date}}generateRecommendation(e,t,n){if(!t)return"Continue test - sample size too small or no significant difference detected";if(e>20)return`Strong winner detected - ${n} shows ${e.toFixed(1)}% improvement. Recommend deploying to all traffic.`;if(e>10)return`Moderate improvement - ${n} shows ${e.toFixed(1)}% improvement. Consider deploying.`;if(e>0)return`Minor improvement - ${n} shows ${e.toFixed(1)}% improvement. May not be worth the complexity.`;return"No improvement detected - consider reverting to control variant"}getTest(e){return this.tests.get(e)}listTests(){return Array.from(this.tests.values())}generateALBListenerRuleCF(e){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:e.variants.map((t)=>({TargetGroupArn:t.targetGroupArn,Weight:t.weight})),TargetGroupStickinessConfig:{Enabled:e.routingStrategy.stickySession||!1,DurationSeconds:e.routingStrategy.sessionDuration?e.routingStrategy.sessionDuration*60:void 0}}}]}}}generateLambdaEdgeFunction(e){return`'use strict';
3587
+ `}class yn{backupPlans=new Map;backupVaults=new Map;restoreJobs=new Map;continuousBackups=new Map;planCounter=0;restoreCounter=0;continuousBackupCounter=0;createVault(e){this.backupVaults.set(e.name,e)}getVault(e){return this.backupVaults.get(e)}createBackupPlan(e){let t=`backup-plan-${Date.now()}-${this.planCounter++}`,n={id:t,...e};return this.backupPlans.set(t,n),n}getBackupPlan(e){return this.backupPlans.get(e)}listBackupPlans(){return Array.from(this.backupPlans.values())}createRDSBackupPlan(e){let{dbInstanceArn:t,schedule:n="0 2 * * *",retentionDays:r=7,vaultName:i="default-vault"}=e;return this.createBackupPlan({name:"RDS Daily Backup",schedule:n,retentionDays:r,vaultName:i,resources:[{resourceArn:t,resourceType:"rds",region:"us-east-1"}],lifecycle:{moveTocoldStorageAfterDays:30,deleteAfterDays:r}})}createDynamoDBBackupPlan(e){let{tableArn:t,schedule:n="0 3 * * *",retentionDays:r=35,crossRegionCopy:i}=e;return this.createBackupPlan({name:"DynamoDB Daily Backup",schedule:n,retentionDays:r,vaultName:"dynamodb-vault",resources:[{resourceArn:t,resourceType:"dynamodb",region:"us-east-1"}],lifecycle:{deleteAfterDays:r},tags:i?{CrossRegionCopy:i.join(",")}:void 0})}createEFSBackupPlan(e){let{fileSystemArn:t,schedule:n="0 1 * * *",retentionDays:r=30}=e;return this.createBackupPlan({name:"EFS Daily Backup",schedule:n,retentionDays:r,vaultName:"efs-vault",resources:[{resourceArn:t,resourceType:"efs",region:"us-east-1"}],lifecycle:{deleteAfterDays:r}})}enableContinuousBackup(e,t=35){let n=`continuous-backup-${Date.now()}-${this.continuousBackupCounter++}`,r={id:n,resourceId:e,enabled:!0,retentionDays:t};return this.continuousBackups.set(n,r),r}getContinuousBackup(e){return this.continuousBackups.get(e)}enablePointInTimeRecovery(e,t){return{enabled:!0,earliestRestorableTime:new Date(Date.now()-604800000),latestRestorableTime:new Date}}async restoreFromBackup(e){let{backupId:t,resourceType:n,targetRegion:r}=e,i={id:`restore-${Date.now()}-${this.restoreCounter++}`,backupId:t,resourceType:n,status:"pending",startTime:new Date,targetRegion:r};return this.restoreJobs.set(i.id,i),setTimeout(()=>{i.status="running"},100),setTimeout(()=>{i.status="completed",i.endTime=new Date},1000),i}async restoreToPointInTime(e){let{sourceResourceArn:t,targetResourceName:n,restoreTime:r,resourceType:i}=e,s={id:`pitr-${Date.now()}-${this.restoreCounter++}`,backupId:`pitr-${r.getTime()}`,resourceType:i,status:"pending",startTime:new Date};return this.restoreJobs.set(s.id,s),console.log(`Restoring ${i} from ${t} to ${n} at ${r.toISOString()}`),setTimeout(()=>{s.status="completed",s.endTime=new Date},2000),s}getRestoreJob(e){return this.restoreJobs.get(e)}listRestoreJobs(){return Array.from(this.restoreJobs.values())}setupCrossRegionReplication(e){let{sourceVault:t,sourceRegion:n,targetRegions:r}=e;console.log("Setting up cross-region replication:"),console.log(` Source: ${t} in ${n}`),console.log(` Targets: ${r.join(", ")}`)}generateBackupVaultCF(e){return{Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:e.name,...e.encryptionKeyArn&&{EncryptionKeyArn:e.encryptionKeyArn},...e.accessPolicy&&{AccessPolicy:e.accessPolicy}}}}generateBackupPlanCF(e){return{Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:e.name,BackupPlanRule:[{RuleName:"DailyBackup",TargetBackupVault:e.vaultName,ScheduleExpression:`cron(${e.schedule})`,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:e.lifecycle?{...e.lifecycle.moveTocoldStorageAfterDays&&{MoveToColdStorageAfterDays:e.lifecycle.moveTocoldStorageAfterDays},...e.lifecycle.deleteAfterDays&&{DeleteAfterDays:e.lifecycle.deleteAfterDays}}:void 0}]},...e.tags&&{BackupPlanTags:e.tags}}}}generateBackupSelectionCF(e){return{Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:{Ref:`BackupPlan${e.id}`},BackupSelection:{SelectionName:`${e.name}Selection`,IamRoleArn:"arn:aws:iam::123456789012:role/service-role/AWSBackupDefaultServiceRole",Resources:e.resources.map((t)=>t.resourceArn)}}}}clear(){this.backupPlans.clear(),this.backupVaults.clear(),this.restoreJobs.clear(),this.continuousBackups.clear(),this.planCounter=0,this.restoreCounter=0,this.continuousBackupCounter=0}}var Ec=new yn;class fn{drPlans=new Map;failoverTests=new Map;planCounter=0;testCounter=0;createDRPlan(e){let t=`dr-plan-${Date.now()}-${this.planCounter++}`,n={id:t,...e};return this.drPlans.set(t,n),n}createRDSDRPlan(e){let{primaryDbArn:t,secondaryDbArn:n,primaryRegion:r,secondaryRegion:i,rto:s=60,rpo:a=5}=e;return this.createDRPlan({name:"RDS Multi-Region DR",primaryRegion:r,secondaryRegion:i,rto:s,rpo:a,resources:[{resourceId:"primary-db",resourceType:"rds",primaryArn:t,secondaryArn:n,replicationEnabled:!0}],runbook:this.generateRDSRunbook(r,i),testSchedule:"0 0 1 * *"})}createDynamoDBDRPlan(e){let{tableArn:t,regions:n,rto:r=15,rpo:i=1}=e;return this.createDRPlan({name:"DynamoDB Global Tables DR",primaryRegion:n[0],secondaryRegion:n[1],rto:r,rpo:i,resources:[{resourceId:"dynamodb-table",resourceType:"dynamodb",primaryArn:t,replicationEnabled:!0}],runbook:this.generateDynamoDBRunbook(n)})}generateRDSRunbook(e,t){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 "+e,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 "+t,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(e){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(e,t=!1){let n=this.drPlans.get(e);if(!n)throw Error(`DR plan not found: ${e}`);let r=Date.now(),i=0;console.log(`${t?"[DRY RUN] ":""}Executing failover for plan: ${n.name}`),console.log(`Primary: ${n.primaryRegion} -> Secondary: ${n.secondaryRegion}`),console.log(`RTO: ${n.rto} minutes, RPO: ${n.rpo} minutes`),console.log("");for(let a of n.runbook.steps){if(console.log(`Step ${a.order}: ${a.name}`),console.log(` ${a.description}`),console.log(` Action: ${a.action}`),console.log(` Estimated: ${a.estimatedDuration} minutes`),t)console.log(" [SKIPPED - DRY RUN]");else if(a.automatable)console.log(" [AUTOMATED]");else console.log(" [MANUAL - WAITING]");i++,console.log("")}return{success:!0,duration:(Date.now()-r)/1000/60,completedSteps:i}}scheduleFailoverTest(e,t){let n={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:e,status:"scheduled",startTime:t};return this.failoverTests.set(n.id,n),n}async runFailoverTest(e){let t=this.drPlans.get(e);if(!t)throw Error(`DR plan not found: ${e}`);let n={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:e,status:"running",startTime:new Date,results:[]};this.failoverTests.set(n.id,n),console.log(`Running failover test for plan: ${t.name}`),console.log("This is a non-destructive test using test resources"),console.log("");for(let r of t.runbook.steps){let i=Date.now();console.log(`Testing step ${r.order}: ${r.name}`);let s={step:r.name,status:"success",duration:(Date.now()-i)/1000,message:`Successfully validated step ${r.order}`};n.results.push(s)}return n.status="completed",n.endTime=new Date,n}getDRPlan(e){return this.drPlans.get(e)}listDRPlans(){return Array.from(this.drPlans.values())}getFailoverTest(e){return this.failoverTests.get(e)}listFailoverTests(){return Array.from(this.failoverTests.values())}validateDRPlan(e){let t=[],n=[];if(e.rto<e.rpo)n.push("RTO cannot be less than RPO");if(e.rto>240)t.push("RTO exceeds 4 hours - consider improving recovery time");if(e.rpo>60)t.push("RPO exceeds 1 hour - consider more frequent backups");if(e.resources.length===0)n.push("No resources defined in DR plan");for(let s of e.resources){if(!s.replicationEnabled)t.push(`Resource ${s.resourceId} does not have replication enabled`);if(!s.secondaryArn&&s.resourceType!=="dynamodb")t.push(`Resource ${s.resourceId} does not have secondary resource defined`)}if(e.runbook.steps.length===0)n.push("No recovery steps defined in runbook");let r=e.runbook.steps.reduce((s,a)=>s+a.estimatedDuration,0);if(r>e.rto)t.push(`Estimated recovery duration (${r}m) exceeds RTO (${e.rto}m)`);let i=e.runbook.steps.filter((s)=>!s.automatable);if(i.length>0)t.push(`${i.length} manual steps in runbook - consider automation`);return{valid:n.length===0,warnings:t,errors:n}}clear(){this.drPlans.clear(),this.failoverTests.clear(),this.planCounter=0,this.testCounter=0}}var wc=new fn;class hn{configRules=new Map;configRecorders=new Map;deliveryChannels=new Map;ruleCounter=0;createConfigRecorder(e){return this.configRecorders.set(e.name,e),e}createDeliveryChannel(e){return this.deliveryChannels.set(e.name,e),e}createConfigRule(e){let t=`config-rule-${Date.now()}-${this.ruleCounter++}`,n={id:t,...e};return this.configRules.set(t,n),n}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(e=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:e},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(e){return this.createConfigRule({name:e.name,description:e.description,source:"CUSTOM_LAMBDA",lambdaFunctionArn:e.lambdaFunctionArn,scope:e.resourceTypes?{complianceResourceTypes:e.resourceTypes}:void 0,maxExecutionFrequency:e.maxExecutionFrequency,inputParameters:e.inputParameters})}createCompliancePreset(e){let t=[];switch(e){case"hipaa":t.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createRdsBackupRule(7),this.createVpcFlowLogsRule());break;case"pci-dss":t.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createIamMfaRule(),this.createRootAccountMfaRule(),this.createVpcFlowLogsRule());break;case"sox":t.push(this.createS3VersioningRule(),this.createCloudTrailEnabledRule(),this.createRdsBackupRule(30),this.createIamPasswordPolicyRule());break;case"gdpr":t.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createRdsSnapshotEncryptionRule());break;case"basic":t.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamMfaRule(),this.createRootAccountMfaRule());break}return t}getConfigRule(e){return this.configRules.get(e)}listConfigRules(){return Array.from(this.configRules.values())}getConfigRecorder(e){return this.configRecorders.get(e)}listConfigRecorders(){return Array.from(this.configRecorders.values())}getDeliveryChannel(e){return this.deliveryChannels.get(e)}listDeliveryChannels(){return Array.from(this.deliveryChannels.values())}generateConfigRuleCF(e){let t={Type:"AWS::Config::ConfigRule",Properties:{ConfigRuleName:e.name,Description:e.description,Source:{Owner:e.source==="AWS_MANAGED"?"AWS":"CUSTOM_LAMBDA"}}};if(e.source==="AWS_MANAGED"&&e.identifier)t.Properties.Source.SourceIdentifier=e.identifier;if(e.source==="CUSTOM_LAMBDA"&&e.lambdaFunctionArn)t.Properties.Source.SourceIdentifier=e.lambdaFunctionArn,t.Properties.Source.SourceDetails=[{EventSource:"aws.config",MessageType:"ConfigurationItemChangeNotification"}];if(e.inputParameters)t.Properties.InputParameters=JSON.stringify(e.inputParameters);if(e.scope){if(t.Properties.Scope={},e.scope.complianceResourceTypes)t.Properties.Scope.ComplianceResourceTypes=e.scope.complianceResourceTypes;if(e.scope.tagKey)t.Properties.Scope.TagKey=e.scope.tagKey;if(e.scope.tagValue)t.Properties.Scope.TagValue=e.scope.tagValue}if(e.maxExecutionFrequency)t.Properties.MaximumExecutionFrequency=e.maxExecutionFrequency;return t}generateConfigRecorderCF(e){return{Type:"AWS::Config::ConfigurationRecorder",Properties:{Name:e.name,RoleArn:e.roleArn,RecordingGroup:e.recordingGroup||{AllSupported:!0,IncludeGlobalResourceTypes:!0}}}}generateDeliveryChannelCF(e){return{Type:"AWS::Config::DeliveryChannel",Properties:{Name:e.name,S3BucketName:e.s3BucketName,...e.s3KeyPrefix&&{S3KeyPrefix:e.s3KeyPrefix},...e.snsTopicArn&&{SnsTopicARN:e.snsTopicArn},...e.configSnapshotDeliveryProperties&&{ConfigSnapshotDeliveryProperties:e.configSnapshotDeliveryProperties}}}}clear(){this.configRules.clear(),this.configRecorders.clear(),this.deliveryChannels.clear(),this.ruleCounter=0}}var Ic=new hn;class bn{trails=new Map;trailCounter=0;createTrail(e){let t=`trail-${Date.now()}-${this.trailCounter++}`,n={id:t,...e};return this.trails.set(t,n),n}createOrganizationTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,s3KeyPrefix:"organization-trail",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:e.kmsKeyId,cloudWatchLogsLogGroupArn:e.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:e.cloudWatchLogsRoleArn})}createSecurityAuditTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,s3KeyPrefix:"security-audit",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:e.kmsKeyId,cloudWatchLogsLogGroupArn:e.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:e.cloudWatchLogsRoleArn,eventSelectors:[{readWriteType:"All",includeManagementEvents:!0,excludeManagementEventSources:[]}],insightSelectors:[{insightType:"ApiCallRateInsight"},{insightType:"ApiErrorRateInsight"}]})}createDataEventsTrail(e){let t=[];if(e.s3DataBuckets&&e.s3DataBuckets.length>0)t.push({type:"AWS::S3::Object",values:e.s3DataBuckets.map((n)=>`arn:aws:s3:::${n}/*`)});if(e.lambdaFunctions&&e.lambdaFunctions.length>0)t.push({type:"AWS::Lambda::Function",values:e.lambdaFunctions});return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,s3KeyPrefix:"data-events",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"All",includeManagementEvents:!1,dataResources:t}]})}createAdvancedTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,advancedEventSelectors:e.selectors})}createReadOnlyTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"ReadOnly",includeManagementEvents:!0}]})}createWriteOnlyTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"WriteOnly",includeManagementEvents:!0}]})}getTrail(e){return this.trails.get(e)}listTrails(){return Array.from(this.trails.values())}generateTrailCF(e){let t={Type:"AWS::CloudTrail::Trail",Properties:{TrailName:e.name,S3BucketName:e.s3BucketName,IsLogging:!0,IncludeGlobalServiceEvents:e.includeGlobalServiceEvents??!0,IsMultiRegionTrail:e.isMultiRegionTrail??!0,EnableLogFileValidation:e.enableLogFileValidation??!0}};if(e.s3KeyPrefix)t.Properties.S3KeyPrefix=e.s3KeyPrefix;if(e.cloudWatchLogsLogGroupArn)t.Properties.CloudWatchLogsLogGroupArn=e.cloudWatchLogsLogGroupArn;if(e.cloudWatchLogsRoleArn)t.Properties.CloudWatchLogsRoleArn=e.cloudWatchLogsRoleArn;if(e.snsTopicName)t.Properties.SnsTopicName=e.snsTopicName;if(e.kmsKeyId)t.Properties.KMSKeyId=e.kmsKeyId;if(e.eventSelectors)t.Properties.EventSelectors=e.eventSelectors.map((n)=>({ReadWriteType:n.readWriteType,IncludeManagementEvents:n.includeManagementEvents??!0,...n.dataResources&&{DataResources:n.dataResources.map((r)=>({Type:r.type,Values:r.values}))},...n.excludeManagementEventSources&&{ExcludeManagementEventSources:n.excludeManagementEventSources}}));if(e.insightSelectors)t.Properties.InsightSelectors=e.insightSelectors.map((n)=>({InsightType:n.insightType}));if(e.advancedEventSelectors)t.Properties.AdvancedEventSelectors=e.advancedEventSelectors.map((n)=>({Name:n.name,FieldSelectors:n.fieldSelectors.map((r)=>({Field:r.field,...r.equals&&{Equals:r.equals},...r.startsWith&&{StartsWith:r.startsWith},...r.endsWith&&{EndsWith:r.endsWith},...r.notEquals&&{NotEquals:r.notEquals},...r.notStartsWith&&{NotStartsWith:r.notStartsWith},...r.notEndsWith&&{NotEndsWith:r.notEndsWith}}))}));return t}generateBucketPolicy(e,t){return{Version:"2012-10-17",Statement:[{Sid:"AWSCloudTrailAclCheck",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:GetBucketAcl",Resource:`arn:aws:s3:::${e}`},{Sid:"AWSCloudTrailWrite",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:PutObject",Resource:t.map((n)=>`arn:aws:s3:::${e}/AWSLogs/${n}/*`),Condition:{StringEquals:{"s3:x-amz-acl":"bucket-owner-full-control"}}}]}}clear(){this.trails.clear(),this.trailCounter=0}}var Dc=new bn;class Sn{detectors=new Map;threatIntelSets=new Map;ipSets=new Map;filters=new Map;detectorCounter=0;threatIntelCounter=0;ipSetCounter=0;filterCounter=0;createDetector(e){let t=`detector-${Date.now()}-${this.detectorCounter++}`,n={id:t,...e};return this.detectors.set(t,n),n}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(e){let t=`threat-intel-${Date.now()}-${this.threatIntelCounter++}`,n={id:t,...e};return this.threatIntelSets.set(t,n),n}createIPSet(e){let t=`ip-set-${Date.now()}-${this.ipSetCounter++}`,n={id:t,...e};return this.ipSets.set(t,n),n}createFindingFilter(e){let t=`filter-${Date.now()}-${this.filterCounter++}`,n={id:t,...e};return this.filters.set(t,n),n}createLowSeverityArchiveFilter(e){return this.createFindingFilter({detectorId:e,name:"archive-low-severity",description:"Automatically archive low severity findings",action:"ARCHIVE",rank:1,findingCriteria:{criterion:{severity:{lt:4}}}})}createFindingTypeFilter(e,t,n){return this.createFindingFilter({detectorId:e,name:`filter-finding-types-${n.toLowerCase()}`,description:`${n==="ARCHIVE"?"Archive":"Keep"} specific finding types`,action:n,rank:2,findingCriteria:{criterion:{type:{eq:t}}}})}createTrustedIPFilter(e,t){return this.createFindingFilter({detectorId:e,name:"trusted-ip-addresses",description:"Archive findings from trusted IP addresses",action:"ARCHIVE",rank:3,findingCriteria:{criterion:{"resource.instanceDetails.networkInterfaces.privateIpAddress":{eq:t}}}})}getDetector(e){return this.detectors.get(e)}listDetectors(){return Array.from(this.detectors.values())}getThreatIntelSet(e){return this.threatIntelSets.get(e)}listThreatIntelSets(){return Array.from(this.threatIntelSets.values())}getIPSet(e){return this.ipSets.get(e)}listIPSets(){return Array.from(this.ipSets.values())}getFindingFilter(e){return this.filters.get(e)}listFindingFilters(){return Array.from(this.filters.values())}generateDetectorCF(e){let t={Type:"AWS::GuardDuty::Detector",Properties:{Enable:e.enable}};if(e.findingPublishingFrequency)t.Properties.FindingPublishingFrequency=e.findingPublishingFrequency;if(e.dataSources){if(t.Properties.DataSources={},e.dataSources.s3Logs)t.Properties.DataSources.S3Logs={Enable:e.dataSources.s3Logs.enable};if(e.dataSources.kubernetes)t.Properties.DataSources.Kubernetes={AuditLogs:{Enable:e.dataSources.kubernetes.auditLogs.enable}};if(e.dataSources.malwareProtection)t.Properties.DataSources.MalwareProtection={ScanEc2InstanceWithFindings:{EbsVolumes:{Enable:e.dataSources.malwareProtection.scanEc2InstanceWithFindings.ebsVolumes.enable}}}}if(e.features)t.Properties.Features=e.features.map((n)=>({Name:n.name,Status:n.status,...n.additionalConfiguration&&{AdditionalConfiguration:n.additionalConfiguration}}));return t}generateThreatIntelSetCF(e){return{Type:"AWS::GuardDuty::ThreatIntelSet",Properties:{DetectorId:e.detectorId,Name:e.name,Format:e.format,Location:e.location,Activate:e.activate}}}generateIPSetCF(e){return{Type:"AWS::GuardDuty::IPSet",Properties:{DetectorId:e.detectorId,Name:e.name,Format:e.format,Location:e.location,Activate:e.activate}}}generateFilterCF(e){return{Type:"AWS::GuardDuty::Filter",Properties:{DetectorId:e.detectorId,Name:e.name,Description:e.description,Action:e.action,Rank:e.rank,FindingCriteria:{Criterion:e.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 Nc=new Sn;class xe{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(e){let t=`hub-${Date.now()}-${this.hubCounter++}`,n={id:t,...e};return this.hubs.set(t,n),n}createComprehensiveHub(){return this.createHub({enable:!0,controlFindingGenerator:"SECURITY_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...xe.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...xe.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...xe.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...xe.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(e){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:e.map((t)=>({value:t,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(e,t){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:`Suppress False Positives - ${e}`,description:`Automatically suppress known false positives from ${e}`,actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"SUPPRESSED"},note:{text:"Known false positive - automatically suppressed",updatedBy:"SecurityHub Automation"}}}],criteria:{productName:[{value:e,comparison:"EQUALS"}],title:t.map((n)=>({value:n,comparison:"PREFIX"}))},ruleStatus:"ENABLED",ruleOrder:10}}getHub(e){return this.hubs.get(e)}listHubs(){return Array.from(this.hubs.values())}generateHubCF(e){let t={Type:"AWS::SecurityHub::Hub",Properties:{}};if(e.controlFindingGenerator)t.Properties.ControlFindingGenerator=e.controlFindingGenerator;if(e.enableDefaultStandards!==void 0)t.Properties.EnableDefaultStandards=e.enableDefaultStandards;return t}generateStandardCF(e){let t={Type:"AWS::SecurityHub::Standard",Properties:{StandardsArn:e.arn}};if(e.disabledControls&&e.disabledControls.length>0)t.Properties.DisabledStandardsControls=e.disabledControls.map((n)=>({StandardsControlArn:n,Reason:"Disabled by configuration"}));return t}generateAutomationRuleCF(e){return{Type:"AWS::SecurityHub::AutomationRule",Properties:{RuleName:e.ruleName,Description:e.description,Actions:e.actions.map((t)=>({Type:t.type,FindingFieldsUpdate:t.findingFieldsUpdate})),Criteria:e.criteria,RuleStatus:e.ruleStatus,RuleOrder:e.ruleOrder}}}clear(){this.hubs.clear(),this.hubCounter=0,this.ruleCounter=0}}var xc=new xe;class An{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;createDeployment(e){let t=`bg-deployment-${Date.now()}-${this.deploymentCounter++}`,n={id:t,...e};return this.deployments.set(t,n),n}createALBDeployment(e){return this.createDeployment({name:e.name,blueEnvironment:{name:"blue",targetGroupArn:e.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:e.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:e.listenerArn,switchoverTimeSeconds:0},autoPromote:e.autoPromote,healthCheckConfig:e.healthCheckConfig})}createRoute53Deployment(e){return this.createDeployment({name:e.name,blueEnvironment:{name:"blue",targetGroupArn:e.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:e.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"route53",hostedZoneId:e.hostedZoneId,switchoverTimeSeconds:e.switchoverTimeSeconds||60}})}createECSDeployment(e){return this.createDeployment({name:e.name,blueEnvironment:{name:"blue",targetGroupArn:e.blueTargetGroupArn,taskDefinitionArn:e.blueTaskDefinitionArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:e.greenTargetGroupArn,taskDefinitionArn:e.greenTaskDefinitionArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:e.listenerArn},autoRollback:e.autoRollback??!0})}async executeDeployment(e,t=!1){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!1,errors:[]};console.log(`${t?"[DRY RUN] ":""}Starting blue/green deployment: ${n.name}`),console.log(` Active environment: ${n.activeEnvironment}`),console.log(` Routing type: ${n.routingConfig.type}`);let i=n.activeEnvironment==="blue"?"green":"blue";if(console.log(` Switching to: ${i}`),console.log(`\\n1. Deploying to ${i} environment`),!t)await new Promise((s)=>setTimeout(s,100));if(console.log(`\\n2. Running health checks on ${i} environment`),n.healthCheckConfig){let s=await this.runHealthChecks(n,i,t);if(r.healthChecksPassed=s,!s){if(r.errors?.push("Health checks failed"),r.endTime=new Date,n.autoRollback)console.log(" Auto-rollback enabled - keeping current environment active"),r.rolledBackAt=new Date;return this.recordDeployment(e,r),r}}else r.healthChecksPassed=!0;if(console.log(`\\n3. Switching traffic to ${i} environment`),!t)n.activeEnvironment=i,r.switchedAt=new Date;if(console.log(`\\n4. Monitoring ${i} environment`),!t)await new Promise((s)=>setTimeout(s,100));return r.success=!0,r.endTime=new Date,console.log("\\n✓ Deployment completed successfully"),this.recordDeployment(e,r),r}async rollback(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);let n={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!0,errors:[]};console.log(`Rolling back deployment: ${t.name}`);let r=t.activeEnvironment==="blue"?"green":"blue";return t.activeEnvironment=r,n.success=!0,n.rolledBackAt=new Date,n.endTime=new Date,console.log(` Switched back to: ${r}`),this.recordDeployment(e,n),n}async runHealthChecks(e,t,n){let r=e.healthCheckConfig;if(console.log(` Health check path: ${r.path||"/"}`),console.log(` Healthy threshold: ${r.healthyThreshold}`),console.log(` Interval: ${r.interval}s`),n)return console.log(" [SKIPPED - DRY RUN]"),!0;let i=0,s=r.healthyThreshold+2;for(let a=0;a<s;a++)if(await new Promise((c)=>setTimeout(c,50)),Math.random()>0.1){if(i++,console.log(` Check ${a+1}: ✓ Healthy (${i}/${r.healthyThreshold})`),i>=r.healthyThreshold)return!0}else i=0,console.log(` Check ${a+1}: ✗ Unhealthy`);return!1}recordDeployment(e,t){if(!this.deploymentHistory.has(e))this.deploymentHistory.set(e,[]);this.deploymentHistory.get(e).push(t)}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(e){return this.deploymentHistory.get(e)||[]}generateALBListenerCF(e){let t=e.activeEnvironment==="blue"?e.blueEnvironment:e.greenEnvironment;return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:e.routingConfig.listenerArn,Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",TargetGroupArn:t.targetGroupArn}]}}}generateRoute53RecordSetCF(e,t){return[{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.routingConfig.hostedZoneId,Name:t,Type:"A",SetIdentifier:"blue",Weight:e.activeEnvironment==="blue"?100:0,AliasTarget:{HostedZoneId:e.routingConfig.hostedZoneId,DNSName:e.blueEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}},{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.routingConfig.hostedZoneId,Name:t,Type:"A",SetIdentifier:"green",Weight:e.activeEnvironment==="green"?100:0,AliasTarget:{HostedZoneId:e.routingConfig.hostedZoneId,DNSName:e.greenEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}}]}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var kc=new An;class pt{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(e){let t=`canary-${Date.now()}-${this.deploymentCounter++}`,n={id:t,...e};return this.deployments.set(t,n),n}createLambdaCanaryDeployment(e){let t=e.strategy||"BALANCED",n=pt.Strategies[t].map((r)=>({...r,alarmThresholds:{errorRate:e.errorRateThreshold||1,latencyP99:e.latencyThreshold||1000}}));return this.createDeployment({name:e.name,baselineVersion:{version:"baseline",functionVersionArn:e.baselineVersionArn,weight:100},canaryVersion:{version:"canary",functionVersionArn:e.canaryVersionArn,weight:0},stages:n,currentStage:0,status:"pending",autoPromote:e.autoPromote??!0,autoRollback:!0})}createECSCanaryDeployment(e){let t=e.strategy||"CONSERVATIVE",n=pt.Strategies[t];return this.createDeployment({name:e.name,baselineVersion:{version:"baseline",taskDefinitionArn:e.baselineTaskDefinitionArn,targetGroupArn:e.baselineTargetGroupArn,weight:100},canaryVersion:{version:"canary",taskDefinitionArn:e.canaryTaskDefinitionArn,targetGroupArn:e.canaryTargetGroupArn,weight:0},stages:n,currentStage:0,status:"pending",autoRollback:!0})}async executeDeployment(e,t=!1){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,completedStages:0,rolledBack:!1};console.log(`${t?"[DRY RUN] ":""}Starting canary deployment: ${n.name}`),console.log(` Strategy: ${n.stages.length} stages`),console.log(` Auto-promote: ${n.autoPromote}`),console.log(` Auto-rollback: ${n.autoRollback}`),console.log(""),n.status="in_progress";for(let i=0;i<n.stages.length;i++){let s=n.stages[i];if(n.currentStage=i,console.log(`Stage ${i+1}/${n.stages.length}: ${s.name}`),console.log(` Traffic: ${s.trafficPercentage}% canary, ${100-s.trafficPercentage}% baseline`),console.log(` Duration: ${s.durationMinutes} minutes`),!t)n.baselineVersion.weight=100-s.trafficPercentage,n.canaryVersion.weight=s.trafficPercentage;if(!await this.monitorStage(n,s,t)){if(console.log(" ✗ Stage failed - metrics exceeded thresholds"),n.autoRollback)console.log("\\n Rolling back deployment..."),await this.rollback(e,t),r.rolledBack=!0,r.reason="Metrics exceeded thresholds";return r.endTime=new Date,n.status="rolled_back",this.recordDeployment(e,r),r}console.log(" ✓ Stage completed successfully"),r.completedStages++,console.log("")}return n.status="completed",r.success=!0,r.endTime=new Date,console.log("✓ Canary deployment completed successfully"),this.recordDeployment(e,r),r}async monitorStage(e,t,n){if(console.log(" Monitoring metrics..."),n)return console.log(" [SKIPPED - DRY RUN]"),!0;await new Promise((i)=>setTimeout(i,100));let r={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)*t.trafficPercentage/100)};if(e.metrics=r,console.log(` Baseline: ${r.baselineErrorRate.toFixed(2)}% errors, ${r.baselineLatencyP99.toFixed(0)}ms P99`),console.log(` Canary: ${r.canaryErrorRate.toFixed(2)}% errors, ${r.canaryLatencyP99.toFixed(0)}ms P99`),t.alarmThresholds){let{errorRate:i,latencyP99:s}=t.alarmThresholds;if(i&&r.canaryErrorRate>i)return console.log(` ⚠ Error rate exceeded threshold: ${r.canaryErrorRate.toFixed(2)}% > ${i}%`),!1;if(s&&r.canaryLatencyP99>s)return console.log(` ⚠ Latency P99 exceeded threshold: ${r.canaryLatencyP99.toFixed(0)}ms > ${s}ms`),!1}return!0}async rollback(e,t=!1){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);if(console.log(`${t?"[DRY RUN] ":""}Rolling back canary deployment: ${n.name}`),!t)n.baselineVersion.weight=100,n.canaryVersion.weight=0,n.status="rolled_back";console.log(" Traffic restored to baseline: 100%")}promoteCanary(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);console.log(`Promoting canary to baseline: ${t.name}`);let n=t.baselineVersion;t.baselineVersion=t.canaryVersion,t.canaryVersion=n,t.baselineVersion.weight=100,t.canaryVersion.weight=0,t.status="completed",console.log(" Canary promoted successfully")}recordDeployment(e,t){if(!this.deploymentHistory.has(e))this.deploymentHistory.set(e,[]);this.deploymentHistory.get(e).push(t)}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(e){return this.deploymentHistory.get(e)||[]}generateLambdaAliasCF(e,t){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:{Ref:"LambdaFunction"},Name:t,FunctionVersion:e.canaryVersion.version,RoutingConfig:{AdditionalVersionWeights:[{FunctionVersion:e.baselineVersion.version,FunctionWeight:e.baselineVersion.weight/100}]}}}}generateALBListenerRuleCF(e){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:[{TargetGroupArn:e.baselineVersion.targetGroupArn,Weight:e.baselineVersion.weight},{TargetGroupArn:e.canaryVersion.targetGroupArn,Weight:e.canaryVersion.weight}],TargetGroupStickinessConfig:{Enabled:!1}}}]}}}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var Mc=new pt;class Cn{tests=new Map;testCounter=0;createTest(e){let t=`abtest-${Date.now()}-${this.testCounter++}`,n={id:t,...e};return this.tests.set(t,n),n}createSimpleABTest(e){let t=e.variantTrafficPercentage||50;return this.createTest({name:e.name,description:e.description,variants:[{id:"control",name:"Control",description:"Original version",trafficPercentage:100-t,targetGroupArn:e.controlTargetGroupArn,weight:100-t},{id:"variant-a",name:"Variant A",description:"Test version",trafficPercentage:t,targetGroupArn:e.variantTargetGroupArn,weight:t}],routingStrategy:{type:e.stickySession?"cookie":"random",cookieName:e.stickySession?"ab_variant":void 0,stickySession:e.stickySession??!1,sessionDuration:1440},startTime:new Date,status:"draft"})}createMultivariateTest(e){let t=e.variants.reduce((n,r)=>n+r.trafficPercentage,0);if(t!==100)throw Error(`Traffic percentages must sum to 100, got ${t}`);return this.createTest({name:e.name,description:e.description,variants:e.variants.map((n,r)=>({id:`variant-${r}`,name:n.name,description:n.description,trafficPercentage:n.trafficPercentage,targetGroupArn:n.targetGroupArn,weight:n.trafficPercentage})),routingStrategy:e.routingStrategy||{type:"random",stickySession:!1},startTime:new Date,status:"draft"})}createHeaderBasedTest(e){return this.createTest({name:e.name,description:`Route based on ${e.headerName} header`,variants:[{id:"control",name:"Control",trafficPercentage:50,targetGroupArn:e.controlTargetGroupArn,weight:50},{id:"variant-a",name:"Variant A",trafficPercentage:50,targetGroupArn:e.variantTargetGroupArn,weight:50}],routingStrategy:{type:"header",headerName:e.headerName,stickySession:!1},startTime:new Date,status:"draft"})}createGeoBasedTest(e){return this.createTest({name:e.name,description:"Route based on geographic location",variants:[{id:"control",name:"Control (Rest of World)",trafficPercentage:50,targetGroupArn:e.controlTargetGroupArn,weight:50},{id:"variant-a",name:`Variant A (${e.regions.join(", ")})`,trafficPercentage:50,targetGroupArn:e.variantTargetGroupArn,weight:50}],routingStrategy:{type:"geo",stickySession:!0,sessionDuration:1440},startTime:new Date,status:"draft"})}startTest(e){let t=this.tests.get(e);if(!t)throw Error(`Test not found: ${e}`);if(t.status!=="draft"&&t.status!=="paused")throw Error(`Cannot start test in ${t.status} status`);t.status="active",t.startTime=new Date,console.log(`Started A/B test: ${t.name}`),console.log(` Variants: ${t.variants.length}`),t.variants.forEach((n)=>{console.log(` - ${n.name}: ${n.trafficPercentage}%`)})}pauseTest(e){let t=this.tests.get(e);if(!t)throw Error(`Test not found: ${e}`);t.status="paused",console.log(`Paused A/B test: ${t.name}`)}updateTrafficSplit(e,t,n){let r=this.tests.get(e);if(!r)throw Error(`Test not found: ${e}`);let i=r.variants.find((a)=>a.id===t);if(!i)throw Error(`Variant not found: ${t}`);let s=i.trafficPercentage;i.trafficPercentage=n,i.weight=n,console.log(`Updated ${i.name} traffic: ${s}% → ${n}%`)}analyzeResults(e){let t=this.tests.get(e);if(!t)throw Error(`Test not found: ${e}`);if(!t.metrics)t.metrics=this.collectMetrics(t);let n=t.variants[0],r=0;for(let l of t.variants){let u=t.metrics.variants[l.id];if(u&&u.conversionRate>r)r=u.conversionRate,n=l}let i=t.metrics.variants.control||t.metrics.variants[t.variants[0].id],s=t.metrics.variants[n.id],a=(s.conversionRate-i.conversionRate)/i.conversionRate*100,o=100,c=s.requests>o&&i.requests>o&&Math.abs(a)>10;return{testId:e,winningVariant:n.name,confidence:c?95:75,improvement:a,statisticalSignificance:c,metrics:t.metrics,recommendation:this.generateRecommendation(a,c,n.name)}}declareWinner(e,t){let n=this.tests.get(e);if(!n)throw Error(`Test not found: ${e}`);let r=n.variants.find((i)=>i.id===t);if(!r)throw Error(`Variant not found: ${t}`);n.variants.forEach((i)=>{if(i.id===t)i.trafficPercentage=100,i.weight=100;else i.trafficPercentage=0,i.weight=0}),n.status="completed",n.endTime=new Date,n.winner=t,console.log(`Declared winner: ${r.name}`),console.log(` All traffic now routed to ${r.name}`)}collectMetrics(e){let t={},n=0;for(let r of e.variants){let i=Math.floor(Math.random()*1000)+500,s=Math.floor(i*(Math.random()*0.1+0.05)),a=s/i*100;t[r.id]={requests:i,conversions:s,conversionRate:a,averageLatency:150+Math.random()*100,errorRate:Math.random()*0.5,revenue:s*(Math.random()*50+100)},n+=i}return{variants:t,totalRequests:n,startTime:e.startTime,lastUpdated:new Date}}generateRecommendation(e,t,n){if(!t)return"Continue test - sample size too small or no significant difference detected";if(e>20)return`Strong winner detected - ${n} shows ${e.toFixed(1)}% improvement. Recommend deploying to all traffic.`;if(e>10)return`Moderate improvement - ${n} shows ${e.toFixed(1)}% improvement. Consider deploying.`;if(e>0)return`Minor improvement - ${n} shows ${e.toFixed(1)}% improvement. May not be worth the complexity.`;return"No improvement detected - consider reverting to control variant"}getTest(e){return this.tests.get(e)}listTests(){return Array.from(this.tests.values())}generateALBListenerRuleCF(e){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:e.variants.map((t)=>({TargetGroupArn:t.targetGroupArn,Weight:t.weight})),TargetGroupStickinessConfig:{Enabled:e.routingStrategy.stickySession||!1,DurationSeconds:e.routingStrategy.sessionDuration?e.routingStrategy.sessionDuration*60:void 0}}}]}}}generateLambdaEdgeFunction(e){return`'use strict';
3588
3588
 
3589
3589
  exports.handler = (event, _context, _callback) => {
3590
3590
  const request = event.Records[0].cf.request;
@@ -3641,7 +3641,7 @@ exports.handler = (event, _context, _callback) => {
3641
3641
  | filter @message like /ERROR/
3642
3642
  | stats count() as error_count by @message
3643
3643
  | sort error_count desc
3644
- | limit 20`,logGroupNames:e})}getLogGroup(e){return this.logGroups.get(e)}listLogGroups(){return Array.from(this.logGroups.values())}getInsightsQuery(e){return this.insightsQueries.get(e)}listInsightsQueries(){return Array.from(this.insightsQueries.values())}generateLogGroupCF(e){return{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:e.name,...e.retentionDays&&{RetentionInDays:e.retentionDays},...e.kmsKeyId&&{KmsKeyId:e.kmsKeyId}}}}generateMetricFilterCF(e,t){return{Type:"AWS::Logs::MetricFilter",Properties:{FilterName:t.name,FilterPattern:t.filterPattern,LogGroupName:e.name,MetricTransformations:t.metricTransformations.map((n)=>({MetricName:n.metricName,MetricNamespace:n.metricNamespace,MetricValue:n.metricValue,...n.defaultValue!==void 0&&{DefaultValue:n.defaultValue},...n.unit&&{Unit:n.unit},...n.dimensions&&{Dimensions:n.dimensions}}))}}}generateSubscriptionFilterCF(e){return{Type:"AWS::Logs::SubscriptionFilter",Properties:{FilterName:e.name,FilterPattern:e.filterPattern,LogGroupName:e.logGroupName,DestinationArn:e.destinationArn,...e.roleArn&&{RoleArn:e.roleArn},...e.distribution&&{Distribution:e.distribution}}}}generateQueryDefinitionCF(e){return{Type:"AWS::Logs::QueryDefinition",Properties:{Name:e.name,QueryString:e.query,LogGroupNames:e.logGroupNames}}}createLogAggregation(e,t,n=7){let r=`aggregation-${Date.now()}-${this.logGroupCounter++}`,i=this.createLogGroup({name:e,retentionDays:n});return t.forEach((s)=>{this.createMetricFilter(i.id,{name:s.metric,filterPattern:s.pattern,metricTransformations:[{metricName:s.metric,metricNamespace:"CustomMetrics",metricValue:"1",defaultValue:0,unit:"Count"}]})}),{id:r,logGroup:e,filters:t,retention:n}}clear(){this.logGroups.clear(),this.queries.clear(),this.insightsQueries.clear(),this.logGroupCounter=0,this.filterCounter=0,this.queryCounter=0}}var $c=new Tn;class xe{canaries=new Map;heartbeats=new Map;apiMonitors=new Map;canaryCounter=0;heartbeatCounter=0;apiMonitorCounter=0;alarmCounter=0;static RuntimeVersions={NODEJS_PUPPETEER_3_9:"syn-nodejs-puppeteer-3.9",NODEJS_PUPPETEER_4_0:"syn-nodejs-puppeteer-4.0",PYTHON_SELENIUM_1_3:"syn-python-selenium-1.3"};createCanary(e){let t=`canary-${Date.now()}-${this.canaryCounter++}`,n={id:t,...e};return this.canaries.set(t,n),n}createHeartbeatCanary(e){let t=`
3644
+ | limit 20`,logGroupNames:e})}getLogGroup(e){return this.logGroups.get(e)}listLogGroups(){return Array.from(this.logGroups.values())}getInsightsQuery(e){return this.insightsQueries.get(e)}listInsightsQueries(){return Array.from(this.insightsQueries.values())}generateLogGroupCF(e){return{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:e.name,...e.retentionDays&&{RetentionInDays:e.retentionDays},...e.kmsKeyId&&{KmsKeyId:e.kmsKeyId}}}}generateMetricFilterCF(e,t){return{Type:"AWS::Logs::MetricFilter",Properties:{FilterName:t.name,FilterPattern:t.filterPattern,LogGroupName:e.name,MetricTransformations:t.metricTransformations.map((n)=>({MetricName:n.metricName,MetricNamespace:n.metricNamespace,MetricValue:n.metricValue,...n.defaultValue!==void 0&&{DefaultValue:n.defaultValue},...n.unit&&{Unit:n.unit},...n.dimensions&&{Dimensions:n.dimensions}}))}}}generateSubscriptionFilterCF(e){return{Type:"AWS::Logs::SubscriptionFilter",Properties:{FilterName:e.name,FilterPattern:e.filterPattern,LogGroupName:e.logGroupName,DestinationArn:e.destinationArn,...e.roleArn&&{RoleArn:e.roleArn},...e.distribution&&{Distribution:e.distribution}}}}generateQueryDefinitionCF(e){return{Type:"AWS::Logs::QueryDefinition",Properties:{Name:e.name,QueryString:e.query,LogGroupNames:e.logGroupNames}}}createLogAggregation(e,t,n=7){let r=`aggregation-${Date.now()}-${this.logGroupCounter++}`,i=this.createLogGroup({name:e,retentionDays:n});return t.forEach((s)=>{this.createMetricFilter(i.id,{name:s.metric,filterPattern:s.pattern,metricTransformations:[{metricName:s.metric,metricNamespace:"CustomMetrics",metricValue:"1",defaultValue:0,unit:"Count"}]})}),{id:r,logGroup:e,filters:t,retention:n}}clear(){this.logGroups.clear(),this.queries.clear(),this.insightsQueries.clear(),this.logGroupCounter=0,this.filterCounter=0,this.queryCounter=0}}var $c=new Tn;class ke{canaries=new Map;heartbeats=new Map;apiMonitors=new Map;canaryCounter=0;heartbeatCounter=0;apiMonitorCounter=0;alarmCounter=0;static RuntimeVersions={NODEJS_PUPPETEER_3_9:"syn-nodejs-puppeteer-3.9",NODEJS_PUPPETEER_4_0:"syn-nodejs-puppeteer-4.0",PYTHON_SELENIUM_1_3:"syn-python-selenium-1.3"};createCanary(e){let t=`canary-${Date.now()}-${this.canaryCounter++}`,n={id:t,...e};return this.canaries.set(t,n),n}createHeartbeatCanary(e){let t=`
3645
3645
  const synthetics = require('Synthetics');
3646
3646
  const log = require('SyntheticsLogger');
3647
3647
 
@@ -3661,7 +3661,7 @@ const heartbeat = async function () {
3661
3661
  exports.handler = async () => {
3662
3662
  return await heartbeat();
3663
3663
  };
3664
- `;return this.createCanary({name:e.name,description:`Heartbeat monitor for ${e.url}`,runtimeVersion:xe.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:t},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:60,memoryInMB:960,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}createAPICanary(e){let n=`
3664
+ `;return this.createCanary({name:e.name,description:`Heartbeat monitor for ${e.url}`,runtimeVersion:ke.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:t},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:60,memoryInMB:960,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}createAPICanary(e){let n=`
3665
3665
  const synthetics = require('Synthetics');
3666
3666
  const log = require('SyntheticsLogger');
3667
3667
 
@@ -3690,7 +3690,7 @@ const apiCheck = async function () {
3690
3690
  exports.handler = async () => {
3691
3691
  return await apiCheck();
3692
3692
  };
3693
- `;return this.createCanary({name:e.name,description:`API monitor for ${e.baseUrl}`,runtimeVersion:xe.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:n},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:120,memoryInMB:960,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}createVisualRegressionCanary(e){let t=`
3693
+ `;return this.createCanary({name:e.name,description:`API monitor for ${e.baseUrl}`,runtimeVersion:ke.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:n},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:120,memoryInMB:960,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}createVisualRegressionCanary(e){let t=`
3694
3694
  const synthetics = require('Synthetics');
3695
3695
  const log = require('SyntheticsLogger');
3696
3696
 
@@ -3710,7 +3710,7 @@ const visualCheck = async function () {
3710
3710
  exports.handler = async () => {
3711
3711
  return await visualCheck();
3712
3712
  };
3713
- `;return this.createCanary({name:e.name,description:`Visual regression monitor for ${e.url}`,runtimeVersion:xe.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:t},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:120,memoryInMB:1024,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}createWorkflowCanary(e){let n=`
3713
+ `;return this.createCanary({name:e.name,description:`Visual regression monitor for ${e.url}`,runtimeVersion:ke.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:t},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:120,memoryInMB:1024,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}createWorkflowCanary(e){let n=`
3714
3714
  const synthetics = require('Synthetics');
3715
3715
  const log = require('SyntheticsLogger');
3716
3716
 
@@ -3732,7 +3732,7 @@ const workflowCheck = async function () {
3732
3732
  exports.handler = async () => {
3733
3733
  return await workflowCheck();
3734
3734
  };
3735
- `;return this.createCanary({name:e.name,description:e.description,runtimeVersion:xe.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:n},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:180,memoryInMB:1024,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}generateActionScript(e){switch(e.type){case"click":return`await page.click('${e.selector}');`;case"type":return`await page.type('${e.selector}', '${e.value}');`;case"wait":return`await page.waitForTimeout(${e.duration});`;case"waitForSelector":return`await page.waitForSelector('${e.selector}');`;default:return""}}createAlarm(e,t){let n=this.canaries.get(e);if(!n)throw Error(`Canary not found: ${e}`);let i={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...t};if(!n.alarms)n.alarms=[];return n.alarms.push(i),i}getCanary(e){return this.canaries.get(e)}listCanaries(){return Array.from(this.canaries.values())}generateCanaryCF(e){let t={Type:"AWS::Synthetics::Canary",Properties:{Name:e.name,RuntimeVersion:e.runtimeVersion,ExecutionRoleArn:{"Fn::GetAtt":["CanaryExecutionRole","Arn"]},Schedule:{Expression:e.schedule.expression,...e.schedule.durationInSeconds&&{DurationInSeconds:e.schedule.durationInSeconds}},ArtifactS3Location:e.artifactS3Location,StartCanaryAfterCreation:!0}};if(e.code.type==="script")t.Properties.Code={Handler:e.handler,Script:e.code.script};else t.Properties.Code={Handler:e.handler,S3Bucket:e.code.s3Bucket,S3Key:e.code.s3Key,...e.code.s3Version&&{S3ObjectVersion:e.code.s3Version}};if(e.runConfig)t.Properties.RunConfig={TimeoutInSeconds:e.runConfig.timeoutInSeconds,MemoryInMB:e.runConfig.memoryInMB,...e.runConfig.environmentVariables&&{EnvironmentVariables:e.runConfig.environmentVariables},...e.runConfig.activeTracing!==void 0&&{ActiveTracing:e.runConfig.activeTracing}};if(e.vpcConfig)t.Properties.VPCConfig={SubnetIds:e.vpcConfig.subnetIds,SecurityGroupIds:e.vpcConfig.securityGroupIds};if(e.successRetentionPeriod)t.Properties.SuccessRetentionPeriod=e.successRetentionPeriod;if(e.failureRetentionPeriod)t.Properties.FailureRetentionPeriod=e.failureRetentionPeriod;return t}generateCanaryRoleCF(){return{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","arn:aws:iam::aws:policy/CloudWatchSyntheticsFullAccess"],Policies:[{PolicyName:"CanaryS3Policy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:PutObject","s3:GetBucketLocation"],Resource:["arn:aws:s3:::*/*"]}]}}]}}}clear(){this.canaries.clear(),this.heartbeats.clear(),this.apiMonitors.clear(),this.canaryCounter=0,this.heartbeatCounter=0,this.apiMonitorCounter=0,this.alarmCounter=0}}var Bc=new xe;class Ri{plans=new Map;migrations=new Map;planCounter=0;migrationCounter=0;createPlan(e){let t=`migration-plan-${Date.now()}-${this.planCounter++}`,n={id:t,...e};return this.plans.set(t,n),n}createMigration(e){let t=`migration-${Date.now()}-${this.migrationCounter++}`,n=this.generateChecksum(e.up+e.down),r={id:t,checksum:n,...e};return this.migrations.set(t,r),r}createSchemaMigration(e){let{up:t,down:n}=this.generateSchemaSQL(e.changes,e.tableName,e.engine);return this.createMigration({version:e.version,name:e.name,description:`Schema changes for ${e.tableName}`,up:t,down:n})}createDataMigration(e){return this.createMigration({version:e.version,name:e.name,description:e.description,up:e.upSQL,down:e.downSQL})}addMigrationToPlan(e,t){let n=this.plans.get(e);if(!n)throw Error(`Migration plan not found: ${e}`);n.migrations.push(t)}async executePlan(e,t=!1){let n=this.plans.get(e);if(!n)throw Error(`Migration plan not found: ${e}`);let r=Date.now(),i=[],s=[];if(console.log(`${t?"[DRY RUN] ":""}Executing migration plan: ${n.name}`),console.log(`Database: ${n.database.type} - ${n.database.identifier}`),console.log(`Migrations to apply: ${n.migrations.length}
3735
+ `;return this.createCanary({name:e.name,description:e.description,runtimeVersion:ke.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:n},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:180,memoryInMB:1024,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}generateActionScript(e){switch(e.type){case"click":return`await page.click('${e.selector}');`;case"type":return`await page.type('${e.selector}', '${e.value}');`;case"wait":return`await page.waitForTimeout(${e.duration});`;case"waitForSelector":return`await page.waitForSelector('${e.selector}');`;default:return""}}createAlarm(e,t){let n=this.canaries.get(e);if(!n)throw Error(`Canary not found: ${e}`);let i={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...t};if(!n.alarms)n.alarms=[];return n.alarms.push(i),i}getCanary(e){return this.canaries.get(e)}listCanaries(){return Array.from(this.canaries.values())}generateCanaryCF(e){let t={Type:"AWS::Synthetics::Canary",Properties:{Name:e.name,RuntimeVersion:e.runtimeVersion,ExecutionRoleArn:{"Fn::GetAtt":["CanaryExecutionRole","Arn"]},Schedule:{Expression:e.schedule.expression,...e.schedule.durationInSeconds&&{DurationInSeconds:e.schedule.durationInSeconds}},ArtifactS3Location:e.artifactS3Location,StartCanaryAfterCreation:!0}};if(e.code.type==="script")t.Properties.Code={Handler:e.handler,Script:e.code.script};else t.Properties.Code={Handler:e.handler,S3Bucket:e.code.s3Bucket,S3Key:e.code.s3Key,...e.code.s3Version&&{S3ObjectVersion:e.code.s3Version}};if(e.runConfig)t.Properties.RunConfig={TimeoutInSeconds:e.runConfig.timeoutInSeconds,MemoryInMB:e.runConfig.memoryInMB,...e.runConfig.environmentVariables&&{EnvironmentVariables:e.runConfig.environmentVariables},...e.runConfig.activeTracing!==void 0&&{ActiveTracing:e.runConfig.activeTracing}};if(e.vpcConfig)t.Properties.VPCConfig={SubnetIds:e.vpcConfig.subnetIds,SecurityGroupIds:e.vpcConfig.securityGroupIds};if(e.successRetentionPeriod)t.Properties.SuccessRetentionPeriod=e.successRetentionPeriod;if(e.failureRetentionPeriod)t.Properties.FailureRetentionPeriod=e.failureRetentionPeriod;return t}generateCanaryRoleCF(){return{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","arn:aws:iam::aws:policy/CloudWatchSyntheticsFullAccess"],Policies:[{PolicyName:"CanaryS3Policy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:PutObject","s3:GetBucketLocation"],Resource:["arn:aws:s3:::*/*"]}]}}]}}}clear(){this.canaries.clear(),this.heartbeats.clear(),this.apiMonitors.clear(),this.canaryCounter=0,this.heartbeatCounter=0,this.apiMonitorCounter=0,this.alarmCounter=0}}var Bc=new ke;class Ri{plans=new Map;migrations=new Map;planCounter=0;migrationCounter=0;createPlan(e){let t=`migration-plan-${Date.now()}-${this.planCounter++}`,n={id:t,...e};return this.plans.set(t,n),n}createMigration(e){let t=`migration-${Date.now()}-${this.migrationCounter++}`,n=this.generateChecksum(e.up+e.down),r={id:t,checksum:n,...e};return this.migrations.set(t,r),r}createSchemaMigration(e){let{up:t,down:n}=this.generateSchemaSQL(e.changes,e.tableName,e.engine);return this.createMigration({version:e.version,name:e.name,description:`Schema changes for ${e.tableName}`,up:t,down:n})}createDataMigration(e){return this.createMigration({version:e.version,name:e.name,description:e.description,up:e.upSQL,down:e.downSQL})}addMigrationToPlan(e,t){let n=this.plans.get(e);if(!n)throw Error(`Migration plan not found: ${e}`);n.migrations.push(t)}async executePlan(e,t=!1){let n=this.plans.get(e);if(!n)throw Error(`Migration plan not found: ${e}`);let r=Date.now(),i=[],s=[];if(console.log(`${t?"[DRY RUN] ":""}Executing migration plan: ${n.name}`),console.log(`Database: ${n.database.type} - ${n.database.identifier}`),console.log(`Migrations to apply: ${n.migrations.length}
3736
3736
  `),n.backupBeforeMigration&&!t)console.log("Creating database backup before migration...");for(let o of n.migrations)try{if(console.log(`Applying migration: ${o.version} - ${o.name}`),!t){if(this.generateChecksum(o.up+o.down)!==o.checksum)throw Error("Migration checksum mismatch - migration has been modified");let l=Date.now();o.appliedAt=new Date,o.executionTimeMs=Date.now()-l,console.log(`✓ Applied in ${o.executionTimeMs}ms
3737
3737
  `)}else console.log(`[SKIPPED - DRY RUN]
3738
3738
  `);i.push(o.version)}catch(c){if(console.error(`✗ Failed: ${c instanceof Error?c.message:String(c)}
@@ -3760,7 +3760,7 @@ Scanning image: ${n}`),console.log(`Scanner: ${t.scanner}`);let r=`scan-result-$
3760
3760
  Scan Results:`),console.log(` Total vulnerabilities: ${s.total}`),console.log(` Critical: ${s.critical}`),console.log(` High: ${s.high}`),console.log(` Medium: ${s.medium}`),console.log(` Low: ${s.low}`),console.log(` Status: ${a?"✓ PASSED":"✗ FAILED"}`),o}simulateVulnerabilities(e){let t=[];if(e.scanner==="trivy"||e.scanner==="ecr")t.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}),t.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 t}evaluateScanResult(e,t){if(!e.failOnSeverity)return!0;switch(e.failOnSeverity){case"CRITICAL":return t.critical===0;case"HIGH":return t.critical===0&&t.high===0;case"MEDIUM":return t.critical===0&&t.high===0&&t.medium===0;case"LOW":return t.total===0;default:return!0}}createPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,n={id:t,...e};return this.policies.set(t,n),n}createStrictPolicy(e){return this.createPolicy({name:e,allowedSeverities:[],maxCritical:0,maxHigh:0,blockOnFailure:!0,exemptions:[]})}createPermissivePolicy(e){return this.createPolicy({name:e,allowedSeverities:["CRITICAL","HIGH","MEDIUM","LOW"],maxCritical:5,maxHigh:10,blockOnFailure:!1,exemptions:[]})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getResult(e){return this.results.get(e)}listResults(){return Array.from(this.results.values())}generateECRScanCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e.repository,ImageScanningConfiguration:{ScanOnPush:e.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 Vb=new Ni;class xi{configs=new Map;multiStageConfigs=new Map;optimizations=new Map;analyses=new Map;configCounter=0;multiStageCounter=0;optimizationCounter=0;analysisCounter=0;createBuildConfig(e){let t=`build-config-${Date.now()}-${this.configCounter++}`,n={id:t,...e};return this.configs.set(t,n),n}createOptimizedBuildConfig(e){let t={type:e.enableCache?"registry":"inline",cacheFrom:e.registry?[`${e.registry}/cache`]:void 0,cacheTo:e.registry?`${e.registry}/cache`:void 0,maxCacheAge:7};return this.createBuildConfig({name:e.name,dockerfile:e.dockerfile,context:".",cacheStrategy:t,buildArgs:{BUILDKIT_INLINE_CACHE:"1"}})}createMultiStageConfig(e){let t=`multi-stage-${Date.now()}-${this.multiStageCounter++}`,n={id:t,...e};return this.multiStageConfigs.set(t,n),n}createNodeMultiStageBuild(e){let t=e.nodeVersion||"18-alpine";return this.createMultiStageConfig({name:e.name,targetStage:e.targetStage||"production",stages:[{name:"dependencies",baseImage:`node:${t}`,workdir:"/app",commands:["COPY package*.json ./","RUN npm ci --only=production"]},{name:"build",baseImage:`node:${t}`,workdir:"/app",commands:["COPY package*.json ./","RUN npm ci","COPY . .","RUN npm run build"]},{name:"production",baseImage:`node:${t}`,workdir:"/app",copyFrom:["dependencies:/app/node_modules","build:/app/dist"],commands:["COPY package*.json ./","ENV NODE_ENV=production",'CMD ["node", "dist/index.js"]']}]})}generateDockerfile(e){let t=this.multiStageConfigs.get(e);if(!t)throw Error(`Multi-stage config not found: ${e}`);let n=[];for(let r of t.stages){if(n.push(`# Stage: ${r.name}`),n.push(`FROM ${r.baseImage} AS ${r.name}`),r.workdir)n.push(`WORKDIR ${r.workdir}`);if(r.env)for(let[i,s]of Object.entries(r.env))n.push(`ENV ${i}=${s}`);for(let i of r.commands)n.push(i);n.push("")}return n.join(`
3761
3761
  `)}analyzeImage(e,t){let n=`analysis-${Date.now()}-${this.analysisCounter++}`,r=t.map((o)=>({...o,cacheable:this.isLayerCacheable(o.command)})),i=r.reduce((o,c)=>o+c.size,0),s=r.filter((o)=>!o.cacheable&&o.size>100).length,a={id:n,imageId:e,layers:r,totalSize:i,unnecessaryLayers:s};return this.analyses.set(n,a),a}isLayerCacheable(e){let t=["FROM","RUN","COPY","ADD","WORKDIR","ENV"],n=["CMD","ENTRYPOINT","LABEL"];for(let r of t)if(e.startsWith(r))return!0;for(let r of n)if(e.startsWith(r))return!1;return!1}generateOptimizations(e){let t=this.analyses.get(e);if(!t)throw Error(`Analysis not found: ${e}`);let n=`optimization-${Date.now()}-${this.optimizationCounter++}`,r=[],i=t.layers.filter((l)=>l.command.startsWith("RUN"));if(i.length>5)r.push({type:"layer_reduction",priority:"high",title:"Combine RUN commands",description:`${i.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 s=t.layers[0];if(s.command.includes("ubuntu")||s.command.includes("debian"))r.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 a=t.layers.filter((l)=>l.command.startsWith("COPY"));if(a.length>0&&a[0].index>3)r.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 ./
3762
3762
  RUN npm install
3763
- COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let o={sizeBefore:t.totalSize,sizeAfter:t.totalSize*0.6,timeBefore:300,timeAfter:120},c={id:n,name:`Optimization for ${t.imageId}`,recommendations:r,estimatedSavings:o};return this.optimizations.set(n,c),c}getBuildConfig(e){return this.configs.get(e)}listBuildConfigs(){return Array.from(this.configs.values())}getMultiStageConfig(e){return this.multiStageConfigs.get(e)}listMultiStageConfigs(){return Array.from(this.multiStageConfigs.values())}getOptimization(e){return this.optimizations.get(e)}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 Hb=new xi;class En{registries=new Map;credentials=new Map;registryCounter=0;credentialsCounter=0;createRegistry(e){let t=`registry-${Date.now()}-${this.registryCounter++}`,n={id:t,...e};return this.registries.set(t,n),n}createECRRepository(e){return this.createRegistry({name:e.name,registryType:"ecr",repositoryUri:`123456789012.dkr.ecr.${e.region||"us-east-1"}.amazonaws.com/${e.name}`,region:e.region||"us-east-1",encryption:{encryptionType:e.encryption||"AES256",kmsKeyId:e.kmsKeyId},scanning:{scanOnPush:e.scanOnPush??!0}})}createManagedRepository(e){let t=this.createECRRepository({name:e.name,region:e.region,scanOnPush:!0,encryption:"KMS"});return t.lifecycle={id:`lifecycle-${Date.now()}`,rules:[{rulePriority:1,description:"Keep only last N images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount||10},action:{type:"expire"}},{rulePriority:2,description:"Remove images older than N days",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays||30,countUnit:"days"},action:{type:"expire"}}]},t}enableReplication(e,t){let n=this.registries.get(e);if(!n)throw Error(`Registry not found: ${e}`);return n.replication={enabled:!0,destinations:t},n}createCredentials(e){let t=`creds-${Date.now()}-${this.credentialsCounter++}`,n={id:t,...e};return this.credentials.set(t,n),n}getRegistry(e){return this.registries.get(e)}listRegistries(){return Array.from(this.registries.values())}generateECRRepositoryCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e.name,ImageScanningConfiguration:{ScanOnPush:e.scanning?.scanOnPush??!1},EncryptionConfiguration:{EncryptionType:e.encryption?.encryptionType||"AES256",...e.encryption?.kmsKeyId&&{KmsKey:e.encryption.kmsKeyId}},ImageTagMutability:"MUTABLE",...e.lifecycle&&{LifecyclePolicy:{LifecyclePolicyText:JSON.stringify({rules:e.lifecycle.rules})}}}}}generateReplicationConfigCF(e){return{Type:"AWS::ECR::ReplicationConfiguration",Properties:{ReplicationConfiguration:{Rules:e.destinations.map((t)=>({Destinations:[{Region:t.region,...t.registryId&&{RegistryId:t.registryId}}]}))}}}}clear(){this.registries.clear(),this.credentials.clear(),this.registryCounter=0,this.credentialsCounter=0}}var _c=new En;class wn{meshes=new Map;virtualNodes=new Map;virtualRouters=new Map;virtualGateways=new Map;meshCounter=0;nodeCounter=0;routerCounter=0;gatewayCounter=0;createMesh(e){let t=`mesh-${Date.now()}-${this.meshCounter++}`,n={id:t,...e};return this.meshes.set(t,n),n}createAppMesh(e){return this.createMesh({name:e.name,meshType:"app_mesh",services:e.services,virtualNodes:[],virtualRouters:[],virtualGateways:[]})}createVirtualNode(e){let t=`vnode-${Date.now()}-${this.nodeCounter++}`,n={id:t,...e};return this.virtualNodes.set(t,n),n}createHTTPVirtualNode(e){return this.createVirtualNode({name:e.name,serviceName:e.serviceName,listeners:[{port:e.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:e.namespace,serviceName:e.serviceName}})}createVirtualRouter(e){let t=`vrouter-${Date.now()}-${this.routerCounter++}`,n={id:t,...e};return this.virtualRouters.set(t,n),n}createCanaryRoute(e){return this.createVirtualRouter({name:e.name,listeners:[{port:e.port,protocol:e.protocol}],routes:[{name:"canary-route",match:{prefix:"/"},action:{weightedTargets:[{virtualNode:e.stableTarget,weight:100-e.canaryWeight},{virtualNode:e.canaryTarget,weight:e.canaryWeight}]},retryPolicy:{maxRetries:3,perRetryTimeout:5000,httpRetryEvents:["server-error","gateway-error"],tcpRetryEvents:["connection-error"]}}]})}createVirtualGateway(e){let t=`vgateway-${Date.now()}-${this.gatewayCounter++}`,n={id:t,...e};return this.virtualGateways.set(t,n),n}createIngressGateway(e){let t={port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3}};if(e.enableTLS&&e.certificateArn)t.tls={mode:"STRICT",certificate:{acm:e.certificateArn}};return this.createVirtualGateway({name:e.name,listeners:[t],logging:{accessLog:{file:{path:"/dev/stdout"}}}})}getMesh(e){return this.meshes.get(e)}listMeshes(){return Array.from(this.meshes.values())}getVirtualNode(e){return this.virtualNodes.get(e)}listVirtualNodes(){return Array.from(this.virtualNodes.values())}generateMeshCF(e){return{Type:"AWS::AppMesh::Mesh",Properties:{MeshName:e.name,Spec:{EgressFilter:{Type:"ALLOW_ALL"}}}}}generateVirtualNodeCF(e,t){return{Type:"AWS::AppMesh::VirtualNode",Properties:{MeshName:t,VirtualNodeName:e.name,Spec:{Listeners:e.listeners.map((n)=>({PortMapping:{Port:n.port,Protocol:n.protocol},...n.healthCheck&&{HealthCheck:{Protocol:n.healthCheck.protocol,...n.healthCheck.path&&{Path:n.healthCheck.path},IntervalMillis:n.healthCheck.interval*1000,TimeoutMillis:n.healthCheck.timeout*1000,HealthyThreshold:n.healthCheck.healthyThreshold,UnhealthyThreshold:n.healthCheck.unhealthyThreshold}}})),ServiceDiscovery:{AWSCloudMap:{NamespaceName:e.serviceDiscovery.namespace,ServiceName:e.serviceDiscovery.serviceName}}}}}}generateVirtualRouterCF(e,t){return{Type:"AWS::AppMesh::VirtualRouter",Properties:{MeshName:t,VirtualRouterName:e.name,Spec:{Listeners:e.listeners.map((n)=>({PortMapping:{Port:n.port,Protocol:n.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 Wc=new wn;class ki{layers=new Map;versions=new Map;permissions=new Map;layerCounter=0;versionCounter=0;permissionCounter=0;createLayer(e){let t=`layer-${Date.now()}-${this.layerCounter++}`,n=1,r={id:t,layerArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:1`,version:1,...e};return this.layers.set(t,r),r}createNodeDependenciesLayer(e){return this.createLayer({layerName:e.layerName,description:"Node.js dependencies layer",compatibleRuntimes:[`nodejs${e.nodeVersion}`],content:{type:"s3",s3Bucket:e.s3Bucket,s3Key:e.s3Key},size:5242880})}createUtilitiesLayer(e){return this.createLayer({layerName:e.layerName,description:"Shared utilities and helpers",compatibleRuntimes:e.runtimes,content:{type:"s3",s3Bucket:e.s3Bucket,s3Key:e.s3Key},size:1048576})}publishVersion(e){let t=this.layers.get(e);if(!t)throw Error(`Layer not found: ${e}`);let n=`version-${Date.now()}-${this.versionCounter++}`,r=t.version+1,i={id:n,layerName:t.layerName,version:r,createdAt:new Date,compatibleRuntimes:t.compatibleRuntimes,size:t.size,codeHash:this.generateHash()};return this.versions.set(n,i),t.version=r,t.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${t.layerName}:${r}`,i}addPermission(e){let t=`permission-${Date.now()}-${this.permissionCounter++}`,n={id:t,layerName:e.layerName,version:e.version,principal:e.principal,action:"lambda:GetLayerVersion",organizationId:e.organizationId};return this.permissions.set(t,n),n}generateHash(){return Math.random().toString(36).substring(2,15)}getLayer(e){return this.layers.get(e)}listLayers(){return Array.from(this.layers.values())}getLayerVersions(e){return Array.from(this.versions.values()).filter((t)=>t.layerName===e)}generateLayerCF(e){return{Type:"AWS::Lambda::LayerVersion",Properties:{LayerName:e.layerName,Description:e.description,Content:e.content.type==="s3"?{S3Bucket:e.content.s3Bucket,S3Key:e.content.s3Key,...e.content.s3ObjectVersion&&{S3ObjectVersion:e.content.s3ObjectVersion}}:{ZipFile:e.content.zipFile},CompatibleRuntimes:e.compatibleRuntimes,...e.licenseInfo&&{LicenseInfo:e.licenseInfo}}}}generateLayerPermissionCF(e){return{Type:"AWS::Lambda::LayerVersionPermission",Properties:{LayerVersionArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:${e.version}`,Action:e.action,Principal:e.principal,...e.organizationId&&{OrganizationId:e.organizationId}}}}clear(){this.layers.clear(),this.versions.clear(),this.permissions.clear(),this.layerCounter=0,this.versionCounter=0,this.permissionCounter=0}}var zb=new ki;class Mi{versions=new Map;aliases=new Map;deployments=new Map;versionCounter=0;aliasCounter=0;deploymentCounter=0;publishVersion(e){let t=`version-${Date.now()}-${this.versionCounter++}`,n=this.getNextVersionNumber(e.functionName),r={id:t,functionName:e.functionName,version:n.toString(),functionArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${n}`,codeHash:this.generateHash(),description:e.description,runtime:e.runtime,memorySize:e.memorySize,timeout:e.timeout,publishedAt:new Date};return this.versions.set(t,r),r}getNextVersionNumber(e){let t=Array.from(this.versions.values()).filter((n)=>n.functionName===e).map((n)=>parseInt(n.version));return t.length>0?Math.max(...t)+1:1}createAlias(e){let t=`alias-${Date.now()}-${this.aliasCounter++}`,n={id:t,aliasArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${e.aliasName}`,revisionId:this.generateHash(),...e};return this.aliases.set(t,n),n}createProductionAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"production",functionVersion:e.version,description:"Production alias"})}createStagingAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"staging",functionVersion:e.version,description:"Staging alias"})}updateAlias(e,t){let n=this.aliases.get(e);if(!n)throw Error(`Alias not found: ${e}`);return n.functionVersion=t,n.revisionId=this.generateHash(),n}configureWeightedRouting(e,t){let n=this.aliases.get(e);if(!n)throw Error(`Alias not found: ${e}`);return n.routingConfig={additionalVersionWeights:t},n}createCanaryDeployment(e){let t=`deployment-${Date.now()}-${this.deploymentCounter++}`,n=Array.from(this.aliases.values()).find((i)=>i.functionName===e.functionName&&i.aliasName===e.aliasName);if(!n)n=this.createAlias({functionName:e.functionName,aliasName:e.aliasName,functionVersion:e.fromVersion});this.configureWeightedRouting(n.id,{[e.toVersion]:e.canaryWeight});let r={id:t,functionName:e.functionName,fromVersion:e.fromVersion,toVersion:e.toVersion,aliasName:e.aliasName,strategy:"canary",status:"in_progress",startedAt:new Date};return this.deployments.set(t,r),r}completeDeployment(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);let n=Array.from(this.aliases.values()).find((r)=>r.functionName===t.functionName&&r.aliasName===t.aliasName);if(n)n.functionVersion=t.toVersion,n.routingConfig=void 0;return t.status="completed",t.completedAt=new Date,t}rollbackDeployment(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);let n=Array.from(this.aliases.values()).find((r)=>r.functionName===t.functionName&&r.aliasName===t.aliasName);if(n)n.functionVersion=t.fromVersion,n.routingConfig=void 0;return t.status="failed",t.completedAt=new Date,t}generateHash(){return Math.random().toString(36).substring(2,15)}getVersion(e){return this.versions.get(e)}listVersions(e){let t=Array.from(this.versions.values());return e?t.filter((n)=>n.functionName===e):t}getAlias(e){return this.aliases.get(e)}listAliases(e){let t=Array.from(this.aliases.values());return e?t.filter((n)=>n.functionName===e):t}generateVersionCF(e){return{Type:"AWS::Lambda::Version",Properties:{FunctionName:e.functionName,Description:e.description}}}generateAliasCF(e){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.functionName,Name:e.aliasName,FunctionVersion:e.functionVersion,Description:e.description,...e.routingConfig&&{RoutingConfig:{AdditionalVersionWeights:Object.entries(e.routingConfig.additionalVersionWeights||{}).map(([t,n])=>({FunctionVersion:t,FunctionWeight:n}))}}}}}clear(){this.versions.clear(),this.aliases.clear(),this.deployments.clear(),this.versionCounter=0,this.aliasCounter=0,this.deploymentCounter=0}}var Jb=new Mi;class Li{configs=new Map;provisionedConfigs=new Map;schedules=new Map;autoScalingConfigs=new Map;configCounter=0;provisionedCounter=0;scheduleCounter=0;autoScalingCounter=0;setReservedConcurrency(e){let t=`concurrency-${Date.now()}-${this.configCounter++}`,n={id:t,functionName:e.functionName,reservedConcurrency:e.reservedConcurrency};return this.configs.set(t,n),n}setProvisionedConcurrency(e){let t=`provisioned-${Date.now()}-${this.provisionedCounter++}`,n={id:t,functionName:e.functionName,qualifier:e.qualifier,provisionedConcurrentExecutions:e.provisionedConcurrentExecutions,status:"pending",lastModified:new Date};return this.provisionedConfigs.set(t,n),setTimeout(()=>{n.status="ready",n.allocatedConcurrency=e.provisionedConcurrentExecutions,n.availableConcurrency=e.provisionedConcurrentExecutions},100),n}configureWarmPool(e){return this.setProvisionedConcurrency({functionName:e.functionName,qualifier:e.alias,provisionedConcurrentExecutions:e.minInstances})}createSchedule(e){let t=`schedule-${Date.now()}-${this.scheduleCounter++}`,n={id:t,...e};return this.schedules.set(t,n),n}createBusinessHoursSchedule(e){return this.createSchedule({name:`${e.functionName}-business-hours`,functionName:e.functionName,qualifier:e.qualifier,schedule:[{name:"business-hours",cronExpression:"0 8 * * MON-FRI",targetConcurrency:e.businessHoursConcurrency},{name:"off-hours",cronExpression:"0 18 * * MON-FRI",targetConcurrency:e.offHoursConcurrency},{name:"weekend",cronExpression:"0 0 * * SAT",targetConcurrency:e.offHoursConcurrency}]})}configureAutoScaling(e){let t=`autoscaling-${Date.now()}-${this.autoScalingCounter++}`,n={id:t,...e};return this.autoScalingConfigs.set(t,n),n}configurePredictiveScaling(e){return this.configureAutoScaling({functionName:e.functionName,qualifier:e.qualifier,minCapacity:e.baselineCapacity,maxCapacity:e.peakCapacity,targetUtilization:0.7,scaleInCooldown:300,scaleOutCooldown:60})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getProvisionedConfig(e){return this.provisionedConfigs.get(e)}listProvisionedConfigs(){return Array.from(this.provisionedConfigs.values())}generateReservedConcurrencyCF(e){return{Type:"AWS::Lambda::Function",Properties:{FunctionName:e.functionName,ReservedConcurrentExecutions:e.reservedConcurrency}}}generateProvisionedConcurrencyCF(e){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.functionName,Name:e.qualifier,ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:e.provisionedConcurrentExecutions}}}}generateAutoScalingTargetCF(e){return{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{ServiceNamespace:"lambda",ResourceId:`function:${e.functionName}:${e.qualifier}`,ScalableDimension:"lambda:function:ProvisionedConcurrentExecutions",MinCapacity:e.minCapacity,MaxCapacity:e.maxCapacity}}}generateAutoScalingPolicyCF(e){return{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e.functionName}-autoscaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:`${e.functionName}AutoScalingTarget`},TargetTrackingScalingPolicyConfiguration:{TargetValue:e.targetUtilization*100,PredefinedMetricSpecification:{PredefinedMetricType:"LambdaProvisionedConcurrencyUtilization"},ScaleInCooldown:e.scaleInCooldown||300,ScaleOutCooldown:e.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 Zb=new Li;class Oi{destinations=new Map;records=new Map;eventBridgeDestinations=new Map;destinationCounter=0;recordCounter=0;eventBridgeCounter=0;configureDestinations(e){let t=`destination-${Date.now()}-${this.destinationCounter++}`,n={id:t,...e};return this.destinations.set(t,n),n}configureSQSDestination(e){let t={type:"sqs",arn:e.queueArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureSNSDestination(e){let t={type:"sns",arn:e.topicArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureEventBridgeDestination(e){let t={type:"eventbridge",arn:e.eventBusArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureLambdaDestination(e){let t={type:"lambda",arn:e.destinationFunctionArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureDLQWithNotification(e){return this.configureDestinations({functionName:e.functionName,failureDestination:{type:"sqs",arn:e.dlqArn},maxEventAge:3600,maxRetries:0})}createEventBridgeIntegration(e){let t=`eventbridge-${Date.now()}-${this.eventBridgeCounter++}`,n={id:t,functionName:e.functionName,eventBusArn:e.eventBusArn,detailType:e.detailType||"Lambda Function Invocation Result",source:e.source||`lambda.${e.functionName}`};return this.eventBridgeDestinations.set(t,n),n}sendToDestination(e){let t=Array.from(this.destinations.values()).find((s)=>s.functionName===e.functionName);if(!t)return null;let n=e.status==="success"?t.successDestination:t.failureDestination;if(!n)return null;let r=`record-${Date.now()}-${this.recordCounter++}`,i={id:r,timestamp:new Date,functionName:e.functionName,requestId:e.requestId,status:e.status,destinationType:n.type,destinationArn:n.arn,payload:e.payload,error:e.error};return this.records.set(r,i),i}getDestination(e){return this.destinations.get(e)}listDestinations(e){let t=Array.from(this.destinations.values());return e?t.filter((n)=>n.functionName===e):t}getDestinationRecords(e){let t=Array.from(this.records.values());return e?t.filter((n)=>n.functionName===e):t}generateEventInvokeConfigCF(e){return{Type:"AWS::Lambda::EventInvokeConfig",Properties:{FunctionName:e.functionName,Qualifier:e.qualifier||"$LATEST",MaximumEventAgeInSeconds:e.maxEventAge||21600,MaximumRetryAttempts:e.maxRetries??2,...e.successDestination&&{DestinationConfig:{OnSuccess:{Destination:e.successDestination.arn}}},...e.failureDestination&&{DestinationConfig:{OnFailure:{Destination:e.failureDestination.arn}}}}}}generateEventBridgeRuleCF(e){return{Type:"AWS::Events::Rule",Properties:{EventBusName:e.eventBusArn.split("/").pop(),EventPattern:{source:[e.source],"detail-type":[e.detailType]},State:"ENABLED",Targets:[{Arn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}`,Id:e.id}]}}}clear(){this.destinations.clear(),this.records.clear(),this.eventBridgeDestinations.clear(),this.destinationCounter=0,this.recordCounter=0,this.eventBridgeCounter=0}}var eS=new Oi;class $i{vpcConfigs=new Map;endpoints=new Map;networkInterfaces=new Map;connectivity=new Map;configCounter=0;endpointCounter=0;eniCounter=0;connectivityCounter=0;configureVPC(e){let t=`vpc-config-${Date.now()}-${this.configCounter++}`,n={id:t,...e};this.vpcConfigs.set(t,n);for(let r of e.subnetIds)this.createNetworkInterface({functionName:e.functionName,subnetId:r});return n}configurePrivateVPC(e){return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.privateSubnetIds,securityGroupIds:[e.securityGroupId],ipv6Allowed:!1})}configureMultiAZVPC(e){if(e.subnetIds.length<2)throw Error("Multi-AZ configuration requires at least 2 subnets");return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds})}createVPCEndpoint(e){let t=`endpoint-${Date.now()}-${this.endpointCounter++}`,n={id:t,...e};return this.endpoints.set(t,n),n}createS3Endpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.s3",endpointType:"Gateway",privateDnsEnabled:!1})}createDynamoDBEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.dynamodb",endpointType:"Gateway",privateDnsEnabled:!1})}createSecretsManagerEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.secretsmanager",endpointType:"Interface",subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds,privateDnsEnabled:!0})}createNetworkInterface(e){let t=`eni-${Date.now()}-${this.eniCounter++}`,n={id:t,functionName:e.functionName,networkInterfaceId:`eni-${Math.random().toString(36).substring(2,15)}`,subnetId:e.subnetId,privateIpAddress:`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`,status:"creating",attachedAt:new Date};return this.networkInterfaces.set(t,n),setTimeout(()=>{n.status="available"},100),n}analyzeConnectivity(e){let t=`connectivity-${Date.now()}-${this.connectivityCounter++}`,n=Array.from(this.vpcConfigs.values()).find((c)=>c.functionName===e.functionName),r=Array.from(this.endpoints.values()).filter((c)=>c.vpcId===n?.vpcId).map((c)=>c.serviceName),i=[],s=e.hasNATGateway??!1,a=e.hasInternetGateway??!1;if(!s&&!a)i.push("Add NAT Gateway for internet access");if(!r.includes("com.amazonaws.us-east-1.s3"))i.push("Add S3 VPC endpoint to reduce NAT costs");if(!r.includes("com.amazonaws.us-east-1.dynamodb"))i.push("Add DynamoDB VPC endpoint for private access");let o={id:t,functionName:e.functionName,hasInternetAccess:s||a,hasNATGateway:s,hasVPCEndpoints:r.length>0,endpoints:r,recommendations:i};return this.connectivity.set(t,o),o}getVPCConfig(e){return this.vpcConfigs.get(e)}listVPCConfigs(e){let t=Array.from(this.vpcConfigs.values());return e?t.filter((n)=>n.functionName===e):t}getNetworkInterfaces(e){return Array.from(this.networkInterfaces.values()).filter((t)=>t.functionName===e)}listVPCEndpoints(e){let t=Array.from(this.endpoints.values());return e?t.filter((n)=>n.vpcId===e):t}generateVPCConfigCF(e){return{VpcConfig:{SubnetIds:e.subnetIds,SecurityGroupIds:e.securityGroupIds,...e.ipv6Allowed&&{Ipv6AllowedForDualStack:!0}}}}generateVPCEndpointCF(e){return{Type:"AWS::EC2::VPCEndpoint",Properties:{VpcId:e.vpcId,ServiceName:e.serviceName,VpcEndpointType:e.endpointType,...e.subnetIds&&{SubnetIds:e.subnetIds},...e.securityGroupIds&&{SecurityGroupIds:e.securityGroupIds},...e.privateDnsEnabled!==void 0&&{PrivateDnsEnabled:e.privateDnsEnabled}}}}generateSecurityGroupCF(e){return{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:e.groupName,GroupDescription:`Security group for Lambda ${e.groupName}`,VpcId:e.vpcId,...e.ingressRules&&{SecurityGroupIngress:e.ingressRules.map((t)=>({IpProtocol:t.protocol,FromPort:t.fromPort,ToPort:t.toPort,...t.cidrIp&&{CidrIp:t.cidrIp},...t.sourceSecurityGroupId&&{SourceSecurityGroupId:t.sourceSecurityGroupId}}))},...e.egressRules&&{SecurityGroupEgress:e.egressRules.map((t)=>({IpProtocol:t.protocol,FromPort:t.fromPort,ToPort:t.toPort,CidrIp:t.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 nS=new $i;class Bi{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(e){let t=`dlq-${Date.now()}-${this.configCounter++}`,n={id:t,...e};return this.dlqConfigs.set(t,n),n}configureSQSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.queueArn,targetType:"sqs",maxReceiveCount:e.maxReceiveCount||3,retentionPeriod:e.retentionPeriod||1209600})}configureSNSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.topicArn,targetType:"sns"})}configureDLQWithAlarm(e){let t=this.configureSQSDLQ({functionName:e.functionName,queueArn:e.queueArn});return this.createDLQAlarm({dlqConfigId:t.id,alarmName:`${e.functionName}-dlq-alarm`,threshold:e.alarmThreshold,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0}),t}sendToDLQ(e){let t=`message-${Date.now()}-${this.messageCounter++}`,n={id:t,timestamp:new Date,...e};return this.messages.set(t,n),n}createDLQAlarm(e){let t=`alarm-${Date.now()}-${this.alarmCounter++}`,n={id:t,...e};return this.alarms.set(t,n),n}createAgeAlarm(e){let t=this.dlqConfigs.get(e.dlqConfigId);if(!t)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:e.dlqConfigId,alarmName:`${t.functionName}-dlq-age-alarm`,threshold:e.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0})}async reprocessMessage(e){let t=this.messages.get(e);if(!t)throw Error(`Message not found: ${e}`);let n=Array.from(this.dlqConfigs.values()).find((s)=>s.functionName===t.functionName);if(!n)throw Error(`DLQ config not found for function: ${t.functionName}`);let r=`reprocess-${Date.now()}-${this.reprocessCounter++}`,i={id:r,dlqConfigId:n.id,messageId:e,status:"pending",startedAt:new Date};return this.reprocessing.set(r,i),setTimeout(()=>{i.status="processing",setTimeout(()=>{let s=Math.random()>0.3;if(i.status=s?"success":"failed",i.completedAt=new Date,!s)i.error="Reprocessing failed - same error occurred";else this.messages.delete(e)},100)},50),i}async batchReprocess(e){let t=this.dlqConfigs.get(e.dlqConfigId);if(!t)throw Error(`DLQ config not found: ${e.dlqConfigId}`);let r=Array.from(this.messages.values()).filter((i)=>i.functionName===t.functionName).slice(0,e.maxMessages||10).map((i)=>this.reprocessMessage(i.id));return Promise.all(r)}getDLQStats(e){let t=this.dlqConfigs.get(e);if(!t)throw Error(`DLQ config not found: ${e}`);let n=Array.from(this.messages.values()).filter((a)=>a.functionName===t.functionName),r={},i=0;for(let a of n)r[a.errorType]=(r[a.errorType]||0)+1,i+=a.attemptCount;let s=n.map((a)=>a.timestamp);return{totalMessages:n.length,oldestMessage:s.length>0?new Date(Math.min(...s.map((a)=>a.getTime()))):void 0,newestMessage:s.length>0?new Date(Math.max(...s.map((a)=>a.getTime()))):void 0,averageAttempts:n.length>0?i/n.length:0,errorTypes:r}}getDLQConfig(e){return this.dlqConfigs.get(e)}listDLQConfigs(){return Array.from(this.dlqConfigs.values())}getDLQMessages(e){let t=this.dlqConfigs.get(e);if(!t)return[];return Array.from(this.messages.values()).filter((n)=>n.functionName===t.functionName)}generateDLQCF(e){return{DeadLetterConfig:{TargetArn:e.targetArn}}}generateSQSDLQCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:`${e.functionName}-dlq`,MessageRetentionPeriod:e.retentionPeriod||1209600,...e.maxReceiveCount&&{RedrivePolicy:{deadLetterTargetArn:e.targetArn,maxReceiveCount:e.maxReceiveCount}}}}}generateDLQAlarmCF(e){let t=this.dlqConfigs.get(e.dlqConfigId);if(!t)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`DLQ alarm for ${t.functionName}`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:e.evaluationPeriods,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:t.targetArn.split(":").pop()}],...e.notificationTopicArn&&{AlarmActions:[e.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 iS=new Bi;class In{policies=new Map;healthChecks=new Map;trafficPolicies=new Map;policyCounter=0;healthCheckCounter=0;trafficPolicyCounter=0;createWeightedPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,n={id:t,type:"weighted",...e};return this.policies.set(t,n),n}createLatencyPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,n={id:t,type:"latency",...e};return this.policies.set(t,n),n}createFailoverPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,n={id:t,type:"failover",...e};return this.policies.set(t,n),n}createGeolocationPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,n={id:t,type:"geolocation",...e};return this.policies.set(t,n),n}createGeoproximityPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,n={id:t,type:"geoproximity",...e};return this.policies.set(t,n),n}createHTTPHealthCheck(e){let t=`health-check-${Date.now()}-${this.healthCheckCounter++}`,n={id:t,type:e.port===443?"https":"http",requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",port:e.port||(e.port===443?443:80),...e};return this.healthChecks.set(t,n),setTimeout(()=>{n.healthCheckStatus=Math.random()>0.2?"Healthy":"Unhealthy"},100),n}createTCPHealthCheck(e){let t=`health-check-${Date.now()}-${this.healthCheckCounter++}`,n={id:t,type:"tcp",fullyQualifiedDomainName:e.ipAddress,requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(t,n),setTimeout(()=>{n.healthCheckStatus=Math.random()>0.1?"Healthy":"Unhealthy"},100),n}createCalculatedHealthCheck(e){let t=`health-check-${Date.now()}-${this.healthCheckCounter++}`,n={id:t,type:"calculated",requestInterval:30,failureThreshold:0,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(t,n),setTimeout(()=>{let i=e.childHealthChecks.filter((s)=>this.healthChecks.get(s)?.healthCheckStatus==="Healthy").length;n.healthCheckStatus=i>=e.healthThreshold?"Healthy":"Unhealthy"},150),n}createTrafficPolicy(e){let t=`traffic-policy-${Date.now()}-${this.trafficPolicyCounter++}`,n={id:t,version:1,...e};return this.trafficPolicies.set(t,n),n}createFailoverTrafficPolicy(e){return this.createTrafficPolicy({name:e.name,document:{recordType:e.recordType||"A",startRule:"failover",endpoints:{primary:{type:"value",value:e.primaryEndpoint},secondary:{type:"value",value:e.secondaryEndpoint}},rules:{failover:{ruleType:"failover",primary:"primary",secondary:"secondary"}}}})}createGeoproximityTrafficPolicy(e){let t={},n=[];return e.locations.forEach((r,i)=>{let s=`endpoint${i}`;t[s]={type:"value",value:r.endpoint},n.push({endpointReference:s,region:r.region,latitude:r.latitude,longitude:r.longitude,bias:r.bias})}),this.createTrafficPolicy({name:e.name,document:{recordType:"A",startRule:"geoproximity",endpoints:t,rules:{geoproximity:{ruleType:"geoproximity",locations:n}}}})}getPolicy(e){return this.policies.get(e)}listPolicies(){return Array.from(this.policies.values())}getHealthCheck(e){return this.healthChecks.get(e)}listHealthChecks(){return Array.from(this.healthChecks.values())}getHealthCheckStatus(e){return this.healthChecks.get(e)?.healthCheckStatus||"Unknown"}generateHealthCheckCF(e){let t={Type:"AWS::Route53::HealthCheck",Properties:{HealthCheckConfig:{Type:e.type.toUpperCase(),RequestInterval:e.requestInterval,FailureThreshold:e.failureThreshold,...e.measureLatency&&{MeasureLatency:!0}},HealthCheckTags:[{Key:"Name",Value:e.name}]}};if(e.type==="calculated"){let n=e;t.Properties.HealthCheckConfig.ChildHealthChecks=n.childHealthChecks,t.Properties.HealthCheckConfig.HealthThreshold=n.healthThreshold}else{if(e.ipAddress)t.Properties.HealthCheckConfig.IPAddress=e.ipAddress;if(e.fullyQualifiedDomainName)t.Properties.HealthCheckConfig.FullyQualifiedDomainName=e.fullyQualifiedDomainName;if(e.port)t.Properties.HealthCheckConfig.Port=e.port;if(e.resourcePath)t.Properties.HealthCheckConfig.ResourcePath=e.resourcePath;if(e.enableSNI)t.Properties.HealthCheckConfig.EnableSNI=!0}return t}generateWeightedRecordSetCF(e){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.hostedZoneId,Name:e.name,Type:e.type,TTL:e.ttl,ResourceRecords:e.resourceRecords,Weight:e.weight,SetIdentifier:e.setIdentifier,...e.healthCheckId&&{HealthCheckId:e.healthCheckId}}}}generateFailoverRecordSetCF(e){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.hostedZoneId,Name:e.name,Type:e.type,TTL:e.ttl,ResourceRecords:e.resourceRecords,Failover:e.failover,SetIdentifier:e.setIdentifier,...e.healthCheckId&&{HealthCheckId:e.healthCheckId}}}}clear(){this.policies.clear(),this.healthChecks.clear(),this.trafficPolicies.clear(),this.policyCounter=0,this.healthCheckCounter=0,this.trafficPolicyCounter=0}}var Vc=new In;class Fi{configs=new Map;ksks=new Map;validations=new Map;configCounter=0;kskCounter=0;validationCounter=0;enableDNSSEC(e){let t=`dnssec-${Date.now()}-${this.configCounter++}`,n={id:t,hostedZoneId:e.hostedZoneId,status:"SIGNING",signingStatus:"Initializing DNSSEC signing"};if(this.configs.set(t,n),e.kmsKeyArn)this.createKSK({name:`ksk-${e.hostedZoneId}`,hostedZoneId:e.hostedZoneId,kmsKeyArn:e.kmsKeyArn});return setTimeout(()=>{n.status="SIGNED",n.signingStatus="DNSSEC signing complete"},100),n}disableDNSSEC(e){let t=this.configs.get(e);if(!t)throw Error(`DNSSEC config not found: ${e}`);return t.status="DELETING",t.signingStatus="Removing DNSSEC signing",setTimeout(()=>{t.status="NOT_SIGNING",t.signingStatus="DNSSEC signing removed"},100),t}createKSK(e){let t=`ksk-${Date.now()}-${this.kskCounter++}`,n={id:t,status:"ACTIVE",flag:257,keyManagementServiceArn:e.kmsKeyArn,digestAlgorithm:2,keyTag:Math.floor(Math.random()*65535),publicKey:this.generatePublicKey(),...e};n.dnskeyRecord=`${n.flag} 3 8 ${n.publicKey}`;let r=this.generateDigest(n.dnskeyRecord);return n.digestValue=r,n.dsRecord=`${n.keyTag} 8 ${n.digestAlgorithm} ${r}`,this.ksks.set(t,n),n}deactivateKSK(e){let t=this.ksks.get(e);if(!t)throw Error(`KSK not found: ${e}`);return t.status="INACTIVE",t}validateDNSSEC(e){let t=`validation-${Date.now()}-${this.validationCounter++}`,n=e.checkDNSKEY!==!1?Math.random()>0.1:!1,r=e.checkRRSIG!==!1?Math.random()>0.1:!1,i=n&&r,s=[];if(!n)s.push("DNSKEY record not found");if(!r)s.push("RRSIG record not found");let a;if(!n&&!r)a="INSECURE";else if(n&&r&&i)a="VALID";else if(n||r)a="BOGUS",s.push("Invalid signature or incomplete DNSSEC chain");else a="INVALID";let o={id:t,domain:e.domain,validationStatus:a,dnskeyPresent:n,rrsigPresent:r,validSignature:i,errors:s};return this.validations.set(t,o),o}getDNSSECConfig(e){return this.configs.get(e)}listDNSSECConfigs(){return Array.from(this.configs.values())}getKSK(e){return this.ksks.get(e)}listKSKs(e){let t=Array.from(this.ksks.values());return e?t.filter((n)=>n.hostedZoneId===e):t}getDSRecord(e){let t=this.ksks.get(e);if(!t||!t.dsRecord)throw Error("DS record not available");return t.dsRecord}generatePublicKey(){let t="";for(let n=0;n<256;n++)t+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return t}generateDigest(e){let n="";for(let r=0;r<64;r++)n+="0123456789ABCDEF".charAt(Math.floor(Math.random()*16));return n}generateDNSSECCF(e){return{Type:"AWS::Route53::DNSSEC",Properties:{HostedZoneId:e.hostedZoneId}}}generateKSKCF(e){return{Type:"AWS::Route53::KeySigningKey",Properties:{Name:e.name,HostedZoneId:e.hostedZoneId,KeyManagementServiceArn:e.keyManagementServiceArn,Status:e.status}}}clear(){this.configs.clear(),this.ksks.clear(),this.validations.clear(),this.configCounter=0,this.kskCounter=0,this.validationCounter=0}}var oS=new Fi;class Gi{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(e){let t=`endpoint-${Date.now()}-${this.endpointCounter++}`,n={id:t,status:"CREATING",...e};return this.endpoints.set(t,n),setTimeout(()=>{n.status="OPERATIONAL",n.ipAddresses.forEach((r)=>{if(!r.ip)r.ip=`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`})},100),n}createInboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"INBOUND",ipAddresses:e.subnetIds.map((t)=>({subnetId:t})),securityGroupIds:e.securityGroupIds})}createOutboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"OUTBOUND",ipAddresses:e.subnetIds.map((t)=>({subnetId:t})),securityGroupIds:e.securityGroupIds})}createResolverRule(e){let t=`rule-${Date.now()}-${this.ruleCounter++}`,n={id:t,status:"CREATING",...e};return this.rules.set(t,n),setTimeout(()=>{n.status="COMPLETE"},100),n}createForwardRule(e){return this.createResolverRule({name:e.name,ruleType:"FORWARD",domainName:e.domainName,targetIps:e.targetIps,resolverEndpointId:e.resolverEndpointId})}createSystemRule(e){return this.createResolverRule({name:e.name,ruleType:"SYSTEM",domainName:e.domainName})}createFirewallDomainList(e){let t=`domain-list-${Date.now()}-${this.domainListCounter++}`,n={id:t,status:"CREATING",...e};return this.domainLists.set(t,n),setTimeout(()=>{n.status="COMPLETE"},100),n}createFirewallRuleGroup(e){let t=`rule-group-${Date.now()}-${this.ruleGroupCounter++}`,n={id:t,name:e.name,rules:e.rules.map((r,i)=>({id:`rule-${t}-${i}`,...r})),shareStatus:"NOT_SHARED"};return this.ruleGroups.set(t,n),n}createBlockRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"BLOCK",blockResponse:e.blockResponse||"NODATA",blockOverrideDomain:e.blockOverrideDomain,firewallDomainListId:e.domainListId}]})}createAllowRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"ALLOW",firewallDomainListId:e.domainListId}]})}createDNSFirewall(e){let t=`firewall-${Date.now()}-${this.firewallCounter++}`,n={id:t,name:e.name,firewallRuleGroupAssociations:e.ruleGroupAssociations.map((r,i)=>({id:`assoc-${t}-${i}`,vpcId:e.vpcId,firewallRuleGroupId:r.firewallRuleGroupId,priority:r.priority,mutationProtection:r.mutationProtection||"DISABLED",status:"COMPLETE"}))};return this.firewalls.set(t,n),n}createMalwareProtectionFirewall(e){let t=this.createFirewallDomainList({name:`${e.name}-malware-domains`,domains:e.maliciousDomains}),n=this.createBlockRule({name:`${e.name}-block-malware`,priority:100,domainListId:t.id,blockResponse:"NXDOMAIN"});return this.createDNSFirewall({name:e.name,vpcId:e.vpcId,ruleGroupAssociations:[{firewallRuleGroupId:n.id,priority:100,mutationProtection:"ENABLED"}]})}getEndpoint(e){return this.endpoints.get(e)}listEndpoints(e){let t=Array.from(this.endpoints.values());return e?t.filter((n)=>n.direction===e):t}getRule(e){return this.rules.get(e)}listRules(){return Array.from(this.rules.values())}getFirewall(e){return this.firewalls.get(e)}listFirewalls(){return Array.from(this.firewalls.values())}generateResolverEndpointCF(e){return{Type:"AWS::Route53Resolver::ResolverEndpoint",Properties:{Name:e.name,Direction:e.direction,IpAddresses:e.ipAddresses.map((t)=>({SubnetId:t.subnetId,...t.ip&&{Ip:t.ip}})),SecurityGroupIds:e.securityGroupIds}}}generateResolverRuleCF(e){return{Type:"AWS::Route53Resolver::ResolverRule",Properties:{Name:e.name,RuleType:e.ruleType,DomainName:e.domainName,...e.targetIps&&{TargetIps:e.targetIps.map((t)=>({Ip:t.ip,Port:t.port||53}))},...e.resolverEndpointId&&{ResolverEndpointId:e.resolverEndpointId}}}}generateFirewallRuleGroupCF(e){return{Type:"AWS::Route53Resolver::FirewallRuleGroup",Properties:{Name:e.name,FirewallRules:e.rules.map((t)=>({Name:t.name,Priority:t.priority,Action:t.action,FirewallDomainListId:t.firewallDomainListId,...t.blockResponse&&{BlockResponse:t.blockResponse},...t.blockOverrideDomain&&{BlockOverrideDomain:t.blockOverrideDomain},...t.blockOverrideTTL&&{BlockOverrideTtl:t.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 lS=new Gi;class _i{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(e){let t=`bounce-${Date.now()}-${this.bounceCounter++}`,n={id:t,...e};if(this.bounces.set(t,n),e.bounceType==="Permanent")this.addToSuppressionList({emailAddress:e.recipient,reason:"BOUNCE"});return n}recordComplaint(e){let t=`complaint-${Date.now()}-${this.complaintCounter++}`,n={id:t,...e};this.complaints.set(t,n);for(let r of e.recipients)this.addToSuppressionList({emailAddress:r,reason:"COMPLAINT"});return n}createBounceHandler(e){let t=`handler-${Date.now()}-${this.handlerCounter++}`,n={id:t,...e};return this.handlers.set(t,n),n}createAutomaticBounceHandler(e){return this.createBounceHandler({name:e.name,bounceThreshold:5,complaintThreshold:0.1,suppressionDuration:2592000,autoSuppress:!0,notificationTopicArn:e.notificationTopicArn})}addToSuppressionList(e){let t=`suppression-${Date.now()}-${this.suppressionCounter++}`,n=e.expirationDays?new Date(Date.now()+e.expirationDays*24*60*60*1000):void 0,r={id:t,emailAddress:e.emailAddress,reason:e.reason,suppressedAt:new Date,expiresAt:n,bounceCount:e.reason==="BOUNCE"?1:0,complaintCount:e.reason==="COMPLAINT"?1:0};return this.suppressionList.set(e.emailAddress,r),r}removeFromSuppressionList(e){return this.suppressionList.delete(e)}isSuppressed(e){let t=this.suppressionList.get(e);if(!t)return!1;if(t.expiresAt&&t.expiresAt<new Date)return this.suppressionList.delete(e),!1;return!0}getBounceStatistics(e,t){let n=Array.from(this.bounces.values()).filter((u)=>u.timestamp>=e&&u.timestamp<=t),r=n.length,i=n.filter((u)=>u.bounceType==="Permanent").length,s=n.filter((u)=>u.bounceType==="Transient").length,a=r*10,o=r/a*100,c=new Map;for(let u of n)c.set(u.recipient,(c.get(u.recipient)||0)+1);let l=Array.from(c.entries()).map(([u,m])=>({email:u,count:m})).sort((u,m)=>m.count-u.count).slice(0,10);return{totalBounces:r,permanentBounces:i,transientBounces:s,bounceRate:o,topRecipients:l}}getComplaintStatistics(e,t){let n=Array.from(this.complaints.values()).filter((c)=>c.timestamp>=e&&c.timestamp<=t),r=n.length,i=new Set;for(let c of n)for(let l of c.recipients)i.add(l);let s=i.size,a=r*1000,o=r/a*100;return{totalComplaints:r,uniqueComplainters:s,complaintRate:o}}calculateReputationMetrics(){let e=`metrics-${Date.now()}-${this.metricsCounter++}`,t=new Date,n=new Date(t.getTime()-86400000),r=this.getBounceStatistics(n,t),i=this.getComplaintStatistics(n,t),s;if(r.bounceRate>10||i.complaintRate>0.5)s="Shutdown";else if(r.bounceRate>5||i.complaintRate>0.1)s="Probation";else if(r.bounceRate>2||i.complaintRate>0.05)s="Warning";else s="Good";let a={id:e,timestamp:t,bounceRate:r.bounceRate,complaintRate:i.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:r.totalBounces*10,reputationStatus:s};return this.metrics.set(e,a),a}getBounces(e){let t=Array.from(this.bounces.values());return e?t.filter((n)=>n.messageId===e):t}getComplaints(e){let t=Array.from(this.complaints.values());return e?t.filter((n)=>n.messageId===e):t}listSuppressionList(e){let t=Array.from(this.suppressionList.values());return e?t.filter((n)=>n.reason===e):t}generateSNSSubscriptionCF(e){return{Type:"AWS::SNS::Subscription",Properties:{TopicArn:e.topicArn,Endpoint:e.endpoint,Protocol:e.protocol}}}generateEventDestinationCF(e){return{Type:"AWS::SES::ConfigurationSetEventDestination",Properties:{ConfigurationSetName:e.configurationSetName,EventDestination:{Name:e.eventDestinationName,Enabled:!0,MatchingEventTypes:e.eventTypes,...e.snsTopicArn&&{SnsDestination:{TopicARN:e.snsTopicArn}},...e.cloudWatchDestination&&{CloudWatchDestination:e.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 dS=new _i;class Wi{events=new Map;campaigns=new Map;reports=new Map;abTests=new Map;eventCounter=0;campaignCounter=0;reportCounter=0;abTestCounter=0;trackEvent(e){let t=`event-${Date.now()}-${this.eventCounter++}`,n={id:t,...e};if(this.events.set(t,n),e.tags?.campaignId)this.updateCampaignStats(e.tags.campaignId,e.eventType);return n}trackOpen(e){return this.trackEvent({...e,eventType:"open",timestamp:new Date})}trackClick(e){return this.trackEvent({...e,eventType:"click",timestamp:new Date})}createCampaign(e){let t=`campaign-${Date.now()}-${this.campaignCounter++}`,n={id:t,sentCount:0,deliveredCount:0,openCount:0,clickCount:0,bounceCount:0,complaintCount:0,createdAt:new Date,...e};return this.campaigns.set(t,n),n}updateCampaignStats(e,t){let n=this.campaigns.get(e);if(!n)return;switch(t){case"send":n.sentCount++;break;case"delivery":n.deliveredCount++;break;case"open":n.openCount++;break;case"click":n.clickCount++;break;case"bounce":n.bounceCount++;break;case"complaint":n.complaintCount++;break}}generateReport(e){let t=`report-${Date.now()}-${this.reportCounter++}`,n=Array.from(this.events.values()).filter((A)=>{let R=A.timestamp>=e.startDate&&A.timestamp<=e.endDate,P=!e.campaignId||A.tags?.campaignId===e.campaignId;return R&&P}),r=n.filter((A)=>A.eventType==="send").length,i=n.filter((A)=>A.eventType==="delivery").length,s=n.filter((A)=>A.eventType==="open").length,a=n.filter((A)=>A.eventType==="click").length,o=n.filter((A)=>A.eventType==="bounce").length,c=n.filter((A)=>A.eventType==="complaint").length,l=r>0?i/r*100:0,u=i>0?s/i*100:0,m=i>0?a/i*100:0,p=s>0?a/s*100:0,g=r>0?o/r*100:0,y=i>0?c/i*100:0,h=new Map;for(let A of n)if(A.eventType==="click"){let R=A;h.set(R.link,(h.get(R.link)||0)+1)}let b=Array.from(h.entries()).map(([A,R])=>({link:A,clicks:R})).sort((A,R)=>R.clicks-A.clicks).slice(0,10),v={desktop:0,mobile:0,tablet:0,unknown:0};for(let A of n)if(A.eventType==="open"||A.eventType==="click"){let R=A.userAgent.toLowerCase();if(R.includes("mobile"))v.mobile++;else if(R.includes("tablet"))v.tablet++;else if(R.includes("mozilla"))v.desktop++;else v.unknown++}let T={id:t,campaignId:e.campaignId,startDate:e.startDate,endDate:e.endDate,totalSent:r,totalDelivered:i,totalOpened:s,totalClicked:a,totalBounced:o,totalComplaints:c,deliveryRate:l,openRate:u,clickRate:m,clickToOpenRate:p,bounceRate:g,complaintRate:y,topLinks:b,deviceBreakdown:v,locationBreakdown:{}};return this.reports.set(t,T),T}createABTest(e){let t=`abtest-${Date.now()}-${this.abTestCounter++}`,n={id:t,name:e.name,variants:e.variants.map((r,i)=>({id:`variant-${t}-${i}`,sentCount:0,openCount:0,clickCount:0,conversionCount:0,...r})),status:"draft"};return this.abTests.set(t,n),n}startABTest(e){let t=this.abTests.get(e);if(!t)throw Error(`A/B test not found: ${e}`);return t.status="running",t.startedAt=new Date,t}completeABTest(e){let t=this.abTests.get(e);if(!t)throw Error(`A/B test not found: ${e}`);let n=t.variants[0],r=0;for(let i of t.variants){let s=i.sentCount>0?i.openCount/i.sentCount:0;if(s>r)r=s,n=i}return t.status="completed",t.completedAt=new Date,t.winner=n.id,t}getCampaign(e){return this.campaigns.get(e)}listCampaigns(){return Array.from(this.campaigns.values())}getEvents(e){let t=Array.from(this.events.values());if(e?.messageId)t=t.filter((n)=>n.messageId===e.messageId);if(e?.eventType)t=t.filter((n)=>n.eventType===e.eventType);if(e?.startDate)t=t.filter((n)=>n.timestamp>=e.startDate);if(e?.endDate)t=t.filter((n)=>n.timestamp<=e.endDate);return t}generateTrackingConfigurationCF(e){return{Type:"AWS::SES::ConfigurationSet",Properties:{Name:e.configurationSetName,...e.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 pS=new Wi;class Vi{dashboards=new Map;warmupPlans=new Map;domainReputations=new Map;dashboardCounter=0;warmupCounter=0;domainCounter=0;getReputationDashboard(){let e=`dashboard-${Date.now()}-${this.dashboardCounter++}`,t=Math.random()*5,n=Math.random()*0.5,r=Math.floor(Math.random()*10),i=Math.max(0,100-t*10-n*100-r*2),s=[];if(t>2)s.push("Reduce bounce rate by cleaning email list");if(n>0.1)s.push("Review email content and unsubscribe process");if(r>5)s.push("Improve email relevance and targeting");let a={id:e,timestamp:new Date,overallScore:i,bounceRate:t,complaintRate:n,spamReports:r,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:s};return this.dashboards.set(e,a),a}checkBlacklists(){return["Spamhaus ZEN","Spamcop","SORBS","Barracuda","URIBL"].map((t)=>({listName:t,listed:Math.random()>0.95,delistUrl:`https://www.${t.toLowerCase().replace(/\s/g,"")}.org/delist`}))}createWarmupPlan(e){let t=`warmup-${Date.now()}-${this.warmupCounter++}`,n=[],r=(e.targetDailyLimit-e.initialDailyLimit)/e.durationDays;for(let s=0;s<e.durationDays;s++)n.push(Math.floor(e.initialDailyLimit+r*s));let i={id:t,name:e.name,startDate:new Date,currentDay:1,totalDays:e.durationDays,dailyLimits:n,currentLimit:n[0],status:"active"};return this.warmupPlans.set(t,i),i}createAggressiveWarmupPlan(e){return this.createWarmupPlan({name:e.name,initialDailyLimit:500,targetDailyLimit:50000,durationDays:14})}createConservativeWarmupPlan(e){return this.createWarmupPlan({name:e.name,initialDailyLimit:200,targetDailyLimit:50000,durationDays:30})}advanceWarmupPlan(e){let t=this.warmupPlans.get(e);if(!t)throw Error(`Warmup plan not found: ${e}`);if(t.currentDay<t.totalDays)t.currentDay++,t.currentLimit=t.dailyLimits[t.currentDay-1];if(t.currentDay>=t.totalDays)t.status="completed";return t}trackDomainReputation(e){let t=`domain-${Date.now()}-${this.domainCounter++}`,n=e.delivered/e.totalSent*100,r=e.delivered>0?e.opened/e.delivered*100:0,i=e.delivered>0?e.clicked/e.delivered*100:0,s=e.bounced/e.totalSent*100,a=e.delivered>0?e.complained/e.delivered*100:0,o=r*0.4+i*0.6,c=Math.max(0,100-s*10-a*100+o*0.2),l={id:t,domain:e.domain,reputationScore:c,totalSent:e.totalSent,deliveryRate:n,openRate:r,clickRate:i,bounceRate:s,complaintRate:a,engagementScore:o};return this.domainReputations.set(e.domain,l),l}getDomainReputation(e){return this.domainReputations.get(e)}listDomainReputations(){return Array.from(this.domainReputations.values())}getWarmupPlan(e){return this.warmupPlans.get(e)}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 yS=new Vi;class Ui{templates=new Map;versions=new Map;tests=new Map;templateCounter=0;testCounter=0;createTemplate(e){let t=`template-${Date.now()}-${this.templateCounter++}`,n=this.extractVariables(e.subject+e.htmlPart+e.textPart),r={id:t,variables:n,createdAt:new Date,updatedAt:new Date,version:1,...e};return this.templates.set(t,r),this.addVersion({templateId:t,version:1,subject:e.subject,htmlPart:e.htmlPart,textPart:e.textPart,createdBy:"system"}),r}createWelcomeTemplate(e){return this.createTemplate({name:e.name,subject:"Welcome to {{companyName}}!",htmlPart:`
3763
+ COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let o={sizeBefore:t.totalSize,sizeAfter:t.totalSize*0.6,timeBefore:300,timeAfter:120},c={id:n,name:`Optimization for ${t.imageId}`,recommendations:r,estimatedSavings:o};return this.optimizations.set(n,c),c}getBuildConfig(e){return this.configs.get(e)}listBuildConfigs(){return Array.from(this.configs.values())}getMultiStageConfig(e){return this.multiStageConfigs.get(e)}listMultiStageConfigs(){return Array.from(this.multiStageConfigs.values())}getOptimization(e){return this.optimizations.get(e)}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 Hb=new xi;class En{registries=new Map;credentials=new Map;registryCounter=0;credentialsCounter=0;createRegistry(e){let t=`registry-${Date.now()}-${this.registryCounter++}`,n={id:t,...e};return this.registries.set(t,n),n}createECRRepository(e){return this.createRegistry({name:e.name,registryType:"ecr",repositoryUri:`123456789012.dkr.ecr.${e.region||"us-east-1"}.amazonaws.com/${e.name}`,region:e.region||"us-east-1",encryption:{encryptionType:e.encryption||"AES256",kmsKeyId:e.kmsKeyId},scanning:{scanOnPush:e.scanOnPush??!0}})}createManagedRepository(e){let t=this.createECRRepository({name:e.name,region:e.region,scanOnPush:!0,encryption:"KMS"});return t.lifecycle={id:`lifecycle-${Date.now()}`,rules:[{rulePriority:1,description:"Keep only last N images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount||10},action:{type:"expire"}},{rulePriority:2,description:"Remove images older than N days",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays||30,countUnit:"days"},action:{type:"expire"}}]},t}enableReplication(e,t){let n=this.registries.get(e);if(!n)throw Error(`Registry not found: ${e}`);return n.replication={enabled:!0,destinations:t},n}createCredentials(e){let t=`creds-${Date.now()}-${this.credentialsCounter++}`,n={id:t,...e};return this.credentials.set(t,n),n}getRegistry(e){return this.registries.get(e)}listRegistries(){return Array.from(this.registries.values())}generateECRRepositoryCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e.name,ImageScanningConfiguration:{ScanOnPush:e.scanning?.scanOnPush??!1},EncryptionConfiguration:{EncryptionType:e.encryption?.encryptionType||"AES256",...e.encryption?.kmsKeyId&&{KmsKey:e.encryption.kmsKeyId}},ImageTagMutability:"MUTABLE",...e.lifecycle&&{LifecyclePolicy:{LifecyclePolicyText:JSON.stringify({rules:e.lifecycle.rules})}}}}}generateReplicationConfigCF(e){return{Type:"AWS::ECR::ReplicationConfiguration",Properties:{ReplicationConfiguration:{Rules:e.destinations.map((t)=>({Destinations:[{Region:t.region,...t.registryId&&{RegistryId:t.registryId}}]}))}}}}clear(){this.registries.clear(),this.credentials.clear(),this.registryCounter=0,this.credentialsCounter=0}}var _c=new En;class wn{meshes=new Map;virtualNodes=new Map;virtualRouters=new Map;virtualGateways=new Map;meshCounter=0;nodeCounter=0;routerCounter=0;gatewayCounter=0;createMesh(e){let t=`mesh-${Date.now()}-${this.meshCounter++}`,n={id:t,...e};return this.meshes.set(t,n),n}createAppMesh(e){return this.createMesh({name:e.name,meshType:"app_mesh",services:e.services,virtualNodes:[],virtualRouters:[],virtualGateways:[]})}createVirtualNode(e){let t=`vnode-${Date.now()}-${this.nodeCounter++}`,n={id:t,...e};return this.virtualNodes.set(t,n),n}createHTTPVirtualNode(e){return this.createVirtualNode({name:e.name,serviceName:e.serviceName,listeners:[{port:e.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:e.namespace,serviceName:e.serviceName}})}createVirtualRouter(e){let t=`vrouter-${Date.now()}-${this.routerCounter++}`,n={id:t,...e};return this.virtualRouters.set(t,n),n}createCanaryRoute(e){return this.createVirtualRouter({name:e.name,listeners:[{port:e.port,protocol:e.protocol}],routes:[{name:"canary-route",match:{prefix:"/"},action:{weightedTargets:[{virtualNode:e.stableTarget,weight:100-e.canaryWeight},{virtualNode:e.canaryTarget,weight:e.canaryWeight}]},retryPolicy:{maxRetries:3,perRetryTimeout:5000,httpRetryEvents:["server-error","gateway-error"],tcpRetryEvents:["connection-error"]}}]})}createVirtualGateway(e){let t=`vgateway-${Date.now()}-${this.gatewayCounter++}`,n={id:t,...e};return this.virtualGateways.set(t,n),n}createIngressGateway(e){let t={port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3}};if(e.enableTLS&&e.certificateArn)t.tls={mode:"STRICT",certificate:{acm:e.certificateArn}};return this.createVirtualGateway({name:e.name,listeners:[t],logging:{accessLog:{file:{path:"/dev/stdout"}}}})}getMesh(e){return this.meshes.get(e)}listMeshes(){return Array.from(this.meshes.values())}getVirtualNode(e){return this.virtualNodes.get(e)}listVirtualNodes(){return Array.from(this.virtualNodes.values())}generateMeshCF(e){return{Type:"AWS::AppMesh::Mesh",Properties:{MeshName:e.name,Spec:{EgressFilter:{Type:"ALLOW_ALL"}}}}}generateVirtualNodeCF(e,t){return{Type:"AWS::AppMesh::VirtualNode",Properties:{MeshName:t,VirtualNodeName:e.name,Spec:{Listeners:e.listeners.map((n)=>({PortMapping:{Port:n.port,Protocol:n.protocol},...n.healthCheck&&{HealthCheck:{Protocol:n.healthCheck.protocol,...n.healthCheck.path&&{Path:n.healthCheck.path},IntervalMillis:n.healthCheck.interval*1000,TimeoutMillis:n.healthCheck.timeout*1000,HealthyThreshold:n.healthCheck.healthyThreshold,UnhealthyThreshold:n.healthCheck.unhealthyThreshold}}})),ServiceDiscovery:{AWSCloudMap:{NamespaceName:e.serviceDiscovery.namespace,ServiceName:e.serviceDiscovery.serviceName}}}}}}generateVirtualRouterCF(e,t){return{Type:"AWS::AppMesh::VirtualRouter",Properties:{MeshName:t,VirtualRouterName:e.name,Spec:{Listeners:e.listeners.map((n)=>({PortMapping:{Port:n.port,Protocol:n.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 Wc=new wn;class ki{layers=new Map;versions=new Map;permissions=new Map;layerCounter=0;versionCounter=0;permissionCounter=0;createLayer(e){let t=`layer-${Date.now()}-${this.layerCounter++}`,n=1,r={id:t,layerArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:1`,version:1,...e};return this.layers.set(t,r),r}createNodeDependenciesLayer(e){return this.createLayer({layerName:e.layerName,description:"Node.js dependencies layer",compatibleRuntimes:[`nodejs${e.nodeVersion}`],content:{type:"s3",s3Bucket:e.s3Bucket,s3Key:e.s3Key},size:5242880})}createUtilitiesLayer(e){return this.createLayer({layerName:e.layerName,description:"Shared utilities and helpers",compatibleRuntimes:e.runtimes,content:{type:"s3",s3Bucket:e.s3Bucket,s3Key:e.s3Key},size:1048576})}publishVersion(e){let t=this.layers.get(e);if(!t)throw Error(`Layer not found: ${e}`);let n=`version-${Date.now()}-${this.versionCounter++}`,r=t.version+1,i={id:n,layerName:t.layerName,version:r,createdAt:new Date,compatibleRuntimes:t.compatibleRuntimes,size:t.size,codeHash:this.generateHash()};return this.versions.set(n,i),t.version=r,t.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${t.layerName}:${r}`,i}addPermission(e){let t=`permission-${Date.now()}-${this.permissionCounter++}`,n={id:t,layerName:e.layerName,version:e.version,principal:e.principal,action:"lambda:GetLayerVersion",organizationId:e.organizationId};return this.permissions.set(t,n),n}generateHash(){return Math.random().toString(36).substring(2,15)}getLayer(e){return this.layers.get(e)}listLayers(){return Array.from(this.layers.values())}getLayerVersions(e){return Array.from(this.versions.values()).filter((t)=>t.layerName===e)}generateLayerCF(e){return{Type:"AWS::Lambda::LayerVersion",Properties:{LayerName:e.layerName,Description:e.description,Content:e.content.type==="s3"?{S3Bucket:e.content.s3Bucket,S3Key:e.content.s3Key,...e.content.s3ObjectVersion&&{S3ObjectVersion:e.content.s3ObjectVersion}}:{ZipFile:e.content.zipFile},CompatibleRuntimes:e.compatibleRuntimes,...e.licenseInfo&&{LicenseInfo:e.licenseInfo}}}}generateLayerPermissionCF(e){return{Type:"AWS::Lambda::LayerVersionPermission",Properties:{LayerVersionArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:${e.version}`,Action:e.action,Principal:e.principal,...e.organizationId&&{OrganizationId:e.organizationId}}}}clear(){this.layers.clear(),this.versions.clear(),this.permissions.clear(),this.layerCounter=0,this.versionCounter=0,this.permissionCounter=0}}var zb=new ki;class Mi{versions=new Map;aliases=new Map;deployments=new Map;versionCounter=0;aliasCounter=0;deploymentCounter=0;publishVersion(e){let t=`version-${Date.now()}-${this.versionCounter++}`,n=this.getNextVersionNumber(e.functionName),r={id:t,functionName:e.functionName,version:n.toString(),functionArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${n}`,codeHash:this.generateHash(),description:e.description,runtime:e.runtime,memorySize:e.memorySize,timeout:e.timeout,publishedAt:new Date};return this.versions.set(t,r),r}getNextVersionNumber(e){let t=Array.from(this.versions.values()).filter((n)=>n.functionName===e).map((n)=>parseInt(n.version));return t.length>0?Math.max(...t)+1:1}createAlias(e){let t=`alias-${Date.now()}-${this.aliasCounter++}`,n={id:t,aliasArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${e.aliasName}`,revisionId:this.generateHash(),...e};return this.aliases.set(t,n),n}createProductionAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"production",functionVersion:e.version,description:"Production alias"})}createStagingAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"staging",functionVersion:e.version,description:"Staging alias"})}updateAlias(e,t){let n=this.aliases.get(e);if(!n)throw Error(`Alias not found: ${e}`);return n.functionVersion=t,n.revisionId=this.generateHash(),n}configureWeightedRouting(e,t){let n=this.aliases.get(e);if(!n)throw Error(`Alias not found: ${e}`);return n.routingConfig={additionalVersionWeights:t},n}createCanaryDeployment(e){let t=`deployment-${Date.now()}-${this.deploymentCounter++}`,n=Array.from(this.aliases.values()).find((i)=>i.functionName===e.functionName&&i.aliasName===e.aliasName);if(!n)n=this.createAlias({functionName:e.functionName,aliasName:e.aliasName,functionVersion:e.fromVersion});this.configureWeightedRouting(n.id,{[e.toVersion]:e.canaryWeight});let r={id:t,functionName:e.functionName,fromVersion:e.fromVersion,toVersion:e.toVersion,aliasName:e.aliasName,strategy:"canary",status:"in_progress",startedAt:new Date};return this.deployments.set(t,r),r}completeDeployment(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);let n=Array.from(this.aliases.values()).find((r)=>r.functionName===t.functionName&&r.aliasName===t.aliasName);if(n)n.functionVersion=t.toVersion,n.routingConfig=void 0;return t.status="completed",t.completedAt=new Date,t}rollbackDeployment(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);let n=Array.from(this.aliases.values()).find((r)=>r.functionName===t.functionName&&r.aliasName===t.aliasName);if(n)n.functionVersion=t.fromVersion,n.routingConfig=void 0;return t.status="failed",t.completedAt=new Date,t}generateHash(){return Math.random().toString(36).substring(2,15)}getVersion(e){return this.versions.get(e)}listVersions(e){let t=Array.from(this.versions.values());return e?t.filter((n)=>n.functionName===e):t}getAlias(e){return this.aliases.get(e)}listAliases(e){let t=Array.from(this.aliases.values());return e?t.filter((n)=>n.functionName===e):t}generateVersionCF(e){return{Type:"AWS::Lambda::Version",Properties:{FunctionName:e.functionName,Description:e.description}}}generateAliasCF(e){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.functionName,Name:e.aliasName,FunctionVersion:e.functionVersion,Description:e.description,...e.routingConfig&&{RoutingConfig:{AdditionalVersionWeights:Object.entries(e.routingConfig.additionalVersionWeights||{}).map(([t,n])=>({FunctionVersion:t,FunctionWeight:n}))}}}}}clear(){this.versions.clear(),this.aliases.clear(),this.deployments.clear(),this.versionCounter=0,this.aliasCounter=0,this.deploymentCounter=0}}var Jb=new Mi;class Li{configs=new Map;provisionedConfigs=new Map;schedules=new Map;autoScalingConfigs=new Map;configCounter=0;provisionedCounter=0;scheduleCounter=0;autoScalingCounter=0;setReservedConcurrency(e){let t=`concurrency-${Date.now()}-${this.configCounter++}`,n={id:t,functionName:e.functionName,reservedConcurrency:e.reservedConcurrency};return this.configs.set(t,n),n}setProvisionedConcurrency(e){let t=`provisioned-${Date.now()}-${this.provisionedCounter++}`,n={id:t,functionName:e.functionName,qualifier:e.qualifier,provisionedConcurrentExecutions:e.provisionedConcurrentExecutions,status:"pending",lastModified:new Date};return this.provisionedConfigs.set(t,n),setTimeout(()=>{n.status="ready",n.allocatedConcurrency=e.provisionedConcurrentExecutions,n.availableConcurrency=e.provisionedConcurrentExecutions},100),n}configureWarmPool(e){return this.setProvisionedConcurrency({functionName:e.functionName,qualifier:e.alias,provisionedConcurrentExecutions:e.minInstances})}createSchedule(e){let t=`schedule-${Date.now()}-${this.scheduleCounter++}`,n={id:t,...e};return this.schedules.set(t,n),n}createBusinessHoursSchedule(e){return this.createSchedule({name:`${e.functionName}-business-hours`,functionName:e.functionName,qualifier:e.qualifier,schedule:[{name:"business-hours",cronExpression:"0 8 * * MON-FRI",targetConcurrency:e.businessHoursConcurrency},{name:"off-hours",cronExpression:"0 18 * * MON-FRI",targetConcurrency:e.offHoursConcurrency},{name:"weekend",cronExpression:"0 0 * * SAT",targetConcurrency:e.offHoursConcurrency}]})}configureAutoScaling(e){let t=`autoscaling-${Date.now()}-${this.autoScalingCounter++}`,n={id:t,...e};return this.autoScalingConfigs.set(t,n),n}configurePredictiveScaling(e){return this.configureAutoScaling({functionName:e.functionName,qualifier:e.qualifier,minCapacity:e.baselineCapacity,maxCapacity:e.peakCapacity,targetUtilization:0.7,scaleInCooldown:300,scaleOutCooldown:60})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getProvisionedConfig(e){return this.provisionedConfigs.get(e)}listProvisionedConfigs(){return Array.from(this.provisionedConfigs.values())}generateReservedConcurrencyCF(e){return{Type:"AWS::Lambda::Function",Properties:{FunctionName:e.functionName,ReservedConcurrentExecutions:e.reservedConcurrency}}}generateProvisionedConcurrencyCF(e){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.functionName,Name:e.qualifier,ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:e.provisionedConcurrentExecutions}}}}generateAutoScalingTargetCF(e){return{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{ServiceNamespace:"lambda",ResourceId:`function:${e.functionName}:${e.qualifier}`,ScalableDimension:"lambda:function:ProvisionedConcurrentExecutions",MinCapacity:e.minCapacity,MaxCapacity:e.maxCapacity}}}generateAutoScalingPolicyCF(e){return{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e.functionName}-autoscaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:`${e.functionName}AutoScalingTarget`},TargetTrackingScalingPolicyConfiguration:{TargetValue:e.targetUtilization*100,PredefinedMetricSpecification:{PredefinedMetricType:"LambdaProvisionedConcurrencyUtilization"},ScaleInCooldown:e.scaleInCooldown||300,ScaleOutCooldown:e.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 Zb=new Li;class Oi{destinations=new Map;records=new Map;eventBridgeDestinations=new Map;destinationCounter=0;recordCounter=0;eventBridgeCounter=0;configureDestinations(e){let t=`destination-${Date.now()}-${this.destinationCounter++}`,n={id:t,...e};return this.destinations.set(t,n),n}configureSQSDestination(e){let t={type:"sqs",arn:e.queueArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureSNSDestination(e){let t={type:"sns",arn:e.topicArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureEventBridgeDestination(e){let t={type:"eventbridge",arn:e.eventBusArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureLambdaDestination(e){let t={type:"lambda",arn:e.destinationFunctionArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureDLQWithNotification(e){return this.configureDestinations({functionName:e.functionName,failureDestination:{type:"sqs",arn:e.dlqArn},maxEventAge:3600,maxRetries:0})}createEventBridgeIntegration(e){let t=`eventbridge-${Date.now()}-${this.eventBridgeCounter++}`,n={id:t,functionName:e.functionName,eventBusArn:e.eventBusArn,detailType:e.detailType||"Lambda Function Invocation Result",source:e.source||`lambda.${e.functionName}`};return this.eventBridgeDestinations.set(t,n),n}sendToDestination(e){let t=Array.from(this.destinations.values()).find((s)=>s.functionName===e.functionName);if(!t)return null;let n=e.status==="success"?t.successDestination:t.failureDestination;if(!n)return null;let r=`record-${Date.now()}-${this.recordCounter++}`,i={id:r,timestamp:new Date,functionName:e.functionName,requestId:e.requestId,status:e.status,destinationType:n.type,destinationArn:n.arn,payload:e.payload,error:e.error};return this.records.set(r,i),i}getDestination(e){return this.destinations.get(e)}listDestinations(e){let t=Array.from(this.destinations.values());return e?t.filter((n)=>n.functionName===e):t}getDestinationRecords(e){let t=Array.from(this.records.values());return e?t.filter((n)=>n.functionName===e):t}generateEventInvokeConfigCF(e){return{Type:"AWS::Lambda::EventInvokeConfig",Properties:{FunctionName:e.functionName,Qualifier:e.qualifier||"$LATEST",MaximumEventAgeInSeconds:e.maxEventAge||21600,MaximumRetryAttempts:e.maxRetries??2,...e.successDestination&&{DestinationConfig:{OnSuccess:{Destination:e.successDestination.arn}}},...e.failureDestination&&{DestinationConfig:{OnFailure:{Destination:e.failureDestination.arn}}}}}}generateEventBridgeRuleCF(e){return{Type:"AWS::Events::Rule",Properties:{EventBusName:e.eventBusArn.split("/").pop(),EventPattern:{source:[e.source],"detail-type":[e.detailType]},State:"ENABLED",Targets:[{Arn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}`,Id:e.id}]}}}clear(){this.destinations.clear(),this.records.clear(),this.eventBridgeDestinations.clear(),this.destinationCounter=0,this.recordCounter=0,this.eventBridgeCounter=0}}var eS=new Oi;class $i{vpcConfigs=new Map;endpoints=new Map;networkInterfaces=new Map;connectivity=new Map;configCounter=0;endpointCounter=0;eniCounter=0;connectivityCounter=0;configureVPC(e){let t=`vpc-config-${Date.now()}-${this.configCounter++}`,n={id:t,...e};this.vpcConfigs.set(t,n);for(let r of e.subnetIds)this.createNetworkInterface({functionName:e.functionName,subnetId:r});return n}configurePrivateVPC(e){return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.privateSubnetIds,securityGroupIds:[e.securityGroupId],ipv6Allowed:!1})}configureMultiAZVPC(e){if(e.subnetIds.length<2)throw Error("Multi-AZ configuration requires at least 2 subnets");return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds})}createVPCEndpoint(e){let t=`endpoint-${Date.now()}-${this.endpointCounter++}`,n={id:t,...e};return this.endpoints.set(t,n),n}createS3Endpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.s3",endpointType:"Gateway",privateDnsEnabled:!1})}createDynamoDBEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.dynamodb",endpointType:"Gateway",privateDnsEnabled:!1})}createSecretsManagerEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.secretsmanager",endpointType:"Interface",subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds,privateDnsEnabled:!0})}createNetworkInterface(e){let t=`eni-${Date.now()}-${this.eniCounter++}`,n={id:t,functionName:e.functionName,networkInterfaceId:`eni-${Math.random().toString(36).substring(2,15)}`,subnetId:e.subnetId,privateIpAddress:`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`,status:"creating",attachedAt:new Date};return this.networkInterfaces.set(t,n),setTimeout(()=>{n.status="available"},100),n}analyzeConnectivity(e){let t=`connectivity-${Date.now()}-${this.connectivityCounter++}`,n=Array.from(this.vpcConfigs.values()).find((c)=>c.functionName===e.functionName),r=Array.from(this.endpoints.values()).filter((c)=>c.vpcId===n?.vpcId).map((c)=>c.serviceName),i=[],s=e.hasNATGateway??!1,a=e.hasInternetGateway??!1;if(!s&&!a)i.push("Add NAT Gateway for internet access");if(!r.includes("com.amazonaws.us-east-1.s3"))i.push("Add S3 VPC endpoint to reduce NAT costs");if(!r.includes("com.amazonaws.us-east-1.dynamodb"))i.push("Add DynamoDB VPC endpoint for private access");let o={id:t,functionName:e.functionName,hasInternetAccess:s||a,hasNATGateway:s,hasVPCEndpoints:r.length>0,endpoints:r,recommendations:i};return this.connectivity.set(t,o),o}getVPCConfig(e){return this.vpcConfigs.get(e)}listVPCConfigs(e){let t=Array.from(this.vpcConfigs.values());return e?t.filter((n)=>n.functionName===e):t}getNetworkInterfaces(e){return Array.from(this.networkInterfaces.values()).filter((t)=>t.functionName===e)}listVPCEndpoints(e){let t=Array.from(this.endpoints.values());return e?t.filter((n)=>n.vpcId===e):t}generateVPCConfigCF(e){return{VpcConfig:{SubnetIds:e.subnetIds,SecurityGroupIds:e.securityGroupIds,...e.ipv6Allowed&&{Ipv6AllowedForDualStack:!0}}}}generateVPCEndpointCF(e){return{Type:"AWS::EC2::VPCEndpoint",Properties:{VpcId:e.vpcId,ServiceName:e.serviceName,VpcEndpointType:e.endpointType,...e.subnetIds&&{SubnetIds:e.subnetIds},...e.securityGroupIds&&{SecurityGroupIds:e.securityGroupIds},...e.privateDnsEnabled!==void 0&&{PrivateDnsEnabled:e.privateDnsEnabled}}}}generateSecurityGroupCF(e){return{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:e.groupName,GroupDescription:`Security group for Lambda ${e.groupName}`,VpcId:e.vpcId,...e.ingressRules&&{SecurityGroupIngress:e.ingressRules.map((t)=>({IpProtocol:t.protocol,FromPort:t.fromPort,ToPort:t.toPort,...t.cidrIp&&{CidrIp:t.cidrIp},...t.sourceSecurityGroupId&&{SourceSecurityGroupId:t.sourceSecurityGroupId}}))},...e.egressRules&&{SecurityGroupEgress:e.egressRules.map((t)=>({IpProtocol:t.protocol,FromPort:t.fromPort,ToPort:t.toPort,CidrIp:t.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 nS=new $i;class Bi{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(e){let t=`dlq-${Date.now()}-${this.configCounter++}`,n={id:t,...e};return this.dlqConfigs.set(t,n),n}configureSQSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.queueArn,targetType:"sqs",maxReceiveCount:e.maxReceiveCount||3,retentionPeriod:e.retentionPeriod||1209600})}configureSNSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.topicArn,targetType:"sns"})}configureDLQWithAlarm(e){let t=this.configureSQSDLQ({functionName:e.functionName,queueArn:e.queueArn});return this.createDLQAlarm({dlqConfigId:t.id,alarmName:`${e.functionName}-dlq-alarm`,threshold:e.alarmThreshold,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0}),t}sendToDLQ(e){let t=`message-${Date.now()}-${this.messageCounter++}`,n={id:t,timestamp:new Date,...e};return this.messages.set(t,n),n}createDLQAlarm(e){let t=`alarm-${Date.now()}-${this.alarmCounter++}`,n={id:t,...e};return this.alarms.set(t,n),n}createAgeAlarm(e){let t=this.dlqConfigs.get(e.dlqConfigId);if(!t)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:e.dlqConfigId,alarmName:`${t.functionName}-dlq-age-alarm`,threshold:e.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0})}async reprocessMessage(e){let t=this.messages.get(e);if(!t)throw Error(`Message not found: ${e}`);let n=Array.from(this.dlqConfigs.values()).find((s)=>s.functionName===t.functionName);if(!n)throw Error(`DLQ config not found for function: ${t.functionName}`);let r=`reprocess-${Date.now()}-${this.reprocessCounter++}`,i={id:r,dlqConfigId:n.id,messageId:e,status:"pending",startedAt:new Date};return this.reprocessing.set(r,i),setTimeout(()=>{i.status="processing",setTimeout(()=>{let s=Math.random()>0.3;if(i.status=s?"success":"failed",i.completedAt=new Date,!s)i.error="Reprocessing failed - same error occurred";else this.messages.delete(e)},100)},50),i}async batchReprocess(e){let t=this.dlqConfigs.get(e.dlqConfigId);if(!t)throw Error(`DLQ config not found: ${e.dlqConfigId}`);let r=Array.from(this.messages.values()).filter((i)=>i.functionName===t.functionName).slice(0,e.maxMessages||10).map((i)=>this.reprocessMessage(i.id));return Promise.all(r)}getDLQStats(e){let t=this.dlqConfigs.get(e);if(!t)throw Error(`DLQ config not found: ${e}`);let n=Array.from(this.messages.values()).filter((a)=>a.functionName===t.functionName),r={},i=0;for(let a of n)r[a.errorType]=(r[a.errorType]||0)+1,i+=a.attemptCount;let s=n.map((a)=>a.timestamp);return{totalMessages:n.length,oldestMessage:s.length>0?new Date(Math.min(...s.map((a)=>a.getTime()))):void 0,newestMessage:s.length>0?new Date(Math.max(...s.map((a)=>a.getTime()))):void 0,averageAttempts:n.length>0?i/n.length:0,errorTypes:r}}getDLQConfig(e){return this.dlqConfigs.get(e)}listDLQConfigs(){return Array.from(this.dlqConfigs.values())}getDLQMessages(e){let t=this.dlqConfigs.get(e);if(!t)return[];return Array.from(this.messages.values()).filter((n)=>n.functionName===t.functionName)}generateDLQCF(e){return{DeadLetterConfig:{TargetArn:e.targetArn}}}generateSQSDLQCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:`${e.functionName}-dlq`,MessageRetentionPeriod:e.retentionPeriod||1209600,...e.maxReceiveCount&&{RedrivePolicy:{deadLetterTargetArn:e.targetArn,maxReceiveCount:e.maxReceiveCount}}}}}generateDLQAlarmCF(e){let t=this.dlqConfigs.get(e.dlqConfigId);if(!t)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`DLQ alarm for ${t.functionName}`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:e.evaluationPeriods,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:t.targetArn.split(":").pop()}],...e.notificationTopicArn&&{AlarmActions:[e.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 iS=new Bi;class In{policies=new Map;healthChecks=new Map;trafficPolicies=new Map;policyCounter=0;healthCheckCounter=0;trafficPolicyCounter=0;createWeightedPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,n={id:t,type:"weighted",...e};return this.policies.set(t,n),n}createLatencyPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,n={id:t,type:"latency",...e};return this.policies.set(t,n),n}createFailoverPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,n={id:t,type:"failover",...e};return this.policies.set(t,n),n}createGeolocationPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,n={id:t,type:"geolocation",...e};return this.policies.set(t,n),n}createGeoproximityPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,n={id:t,type:"geoproximity",...e};return this.policies.set(t,n),n}createHTTPHealthCheck(e){let t=`health-check-${Date.now()}-${this.healthCheckCounter++}`,n={id:t,type:e.port===443?"https":"http",requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",port:e.port||(e.port===443?443:80),...e};return this.healthChecks.set(t,n),setTimeout(()=>{n.healthCheckStatus=Math.random()>0.2?"Healthy":"Unhealthy"},100),n}createTCPHealthCheck(e){let t=`health-check-${Date.now()}-${this.healthCheckCounter++}`,n={id:t,type:"tcp",fullyQualifiedDomainName:e.ipAddress,requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(t,n),setTimeout(()=>{n.healthCheckStatus=Math.random()>0.1?"Healthy":"Unhealthy"},100),n}createCalculatedHealthCheck(e){let t=`health-check-${Date.now()}-${this.healthCheckCounter++}`,n={id:t,type:"calculated",requestInterval:30,failureThreshold:0,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(t,n),setTimeout(()=>{let i=e.childHealthChecks.filter((s)=>this.healthChecks.get(s)?.healthCheckStatus==="Healthy").length;n.healthCheckStatus=i>=e.healthThreshold?"Healthy":"Unhealthy"},150),n}createTrafficPolicy(e){let t=`traffic-policy-${Date.now()}-${this.trafficPolicyCounter++}`,n={id:t,version:1,...e};return this.trafficPolicies.set(t,n),n}createFailoverTrafficPolicy(e){return this.createTrafficPolicy({name:e.name,document:{recordType:e.recordType||"A",startRule:"failover",endpoints:{primary:{type:"value",value:e.primaryEndpoint},secondary:{type:"value",value:e.secondaryEndpoint}},rules:{failover:{ruleType:"failover",primary:"primary",secondary:"secondary"}}}})}createGeoproximityTrafficPolicy(e){let t={},n=[];return e.locations.forEach((r,i)=>{let s=`endpoint${i}`;t[s]={type:"value",value:r.endpoint},n.push({endpointReference:s,region:r.region,latitude:r.latitude,longitude:r.longitude,bias:r.bias})}),this.createTrafficPolicy({name:e.name,document:{recordType:"A",startRule:"geoproximity",endpoints:t,rules:{geoproximity:{ruleType:"geoproximity",locations:n}}}})}getPolicy(e){return this.policies.get(e)}listPolicies(){return Array.from(this.policies.values())}getHealthCheck(e){return this.healthChecks.get(e)}listHealthChecks(){return Array.from(this.healthChecks.values())}getHealthCheckStatus(e){return this.healthChecks.get(e)?.healthCheckStatus||"Unknown"}generateHealthCheckCF(e){let t={Type:"AWS::Route53::HealthCheck",Properties:{HealthCheckConfig:{Type:e.type.toUpperCase(),RequestInterval:e.requestInterval,FailureThreshold:e.failureThreshold,...e.measureLatency&&{MeasureLatency:!0}},HealthCheckTags:[{Key:"Name",Value:e.name}]}};if(e.type==="calculated"){let n=e;t.Properties.HealthCheckConfig.ChildHealthChecks=n.childHealthChecks,t.Properties.HealthCheckConfig.HealthThreshold=n.healthThreshold}else{if(e.ipAddress)t.Properties.HealthCheckConfig.IPAddress=e.ipAddress;if(e.fullyQualifiedDomainName)t.Properties.HealthCheckConfig.FullyQualifiedDomainName=e.fullyQualifiedDomainName;if(e.port)t.Properties.HealthCheckConfig.Port=e.port;if(e.resourcePath)t.Properties.HealthCheckConfig.ResourcePath=e.resourcePath;if(e.enableSNI)t.Properties.HealthCheckConfig.EnableSNI=!0}return t}generateWeightedRecordSetCF(e){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.hostedZoneId,Name:e.name,Type:e.type,TTL:e.ttl,ResourceRecords:e.resourceRecords,Weight:e.weight,SetIdentifier:e.setIdentifier,...e.healthCheckId&&{HealthCheckId:e.healthCheckId}}}}generateFailoverRecordSetCF(e){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.hostedZoneId,Name:e.name,Type:e.type,TTL:e.ttl,ResourceRecords:e.resourceRecords,Failover:e.failover,SetIdentifier:e.setIdentifier,...e.healthCheckId&&{HealthCheckId:e.healthCheckId}}}}clear(){this.policies.clear(),this.healthChecks.clear(),this.trafficPolicies.clear(),this.policyCounter=0,this.healthCheckCounter=0,this.trafficPolicyCounter=0}}var Vc=new In;class Fi{configs=new Map;ksks=new Map;validations=new Map;configCounter=0;kskCounter=0;validationCounter=0;enableDNSSEC(e){let t=`dnssec-${Date.now()}-${this.configCounter++}`,n={id:t,hostedZoneId:e.hostedZoneId,status:"SIGNING",signingStatus:"Initializing DNSSEC signing"};if(this.configs.set(t,n),e.kmsKeyArn)this.createKSK({name:`ksk-${e.hostedZoneId}`,hostedZoneId:e.hostedZoneId,kmsKeyArn:e.kmsKeyArn});return setTimeout(()=>{n.status="SIGNED",n.signingStatus="DNSSEC signing complete"},100),n}disableDNSSEC(e){let t=this.configs.get(e);if(!t)throw Error(`DNSSEC config not found: ${e}`);return t.status="DELETING",t.signingStatus="Removing DNSSEC signing",setTimeout(()=>{t.status="NOT_SIGNING",t.signingStatus="DNSSEC signing removed"},100),t}createKSK(e){let t=`ksk-${Date.now()}-${this.kskCounter++}`,n={id:t,status:"ACTIVE",flag:257,keyManagementServiceArn:e.kmsKeyArn,digestAlgorithm:2,keyTag:Math.floor(Math.random()*65535),publicKey:this.generatePublicKey(),...e};n.dnskeyRecord=`${n.flag} 3 8 ${n.publicKey}`;let r=this.generateDigest(n.dnskeyRecord);return n.digestValue=r,n.dsRecord=`${n.keyTag} 8 ${n.digestAlgorithm} ${r}`,this.ksks.set(t,n),n}deactivateKSK(e){let t=this.ksks.get(e);if(!t)throw Error(`KSK not found: ${e}`);return t.status="INACTIVE",t}validateDNSSEC(e){let t=`validation-${Date.now()}-${this.validationCounter++}`,n=e.checkDNSKEY!==!1?Math.random()>0.1:!1,r=e.checkRRSIG!==!1?Math.random()>0.1:!1,i=n&&r,s=[];if(!n)s.push("DNSKEY record not found");if(!r)s.push("RRSIG record not found");let a;if(!n&&!r)a="INSECURE";else if(n&&r&&i)a="VALID";else if(n||r)a="BOGUS",s.push("Invalid signature or incomplete DNSSEC chain");else a="INVALID";let o={id:t,domain:e.domain,validationStatus:a,dnskeyPresent:n,rrsigPresent:r,validSignature:i,errors:s};return this.validations.set(t,o),o}getDNSSECConfig(e){return this.configs.get(e)}listDNSSECConfigs(){return Array.from(this.configs.values())}getKSK(e){return this.ksks.get(e)}listKSKs(e){let t=Array.from(this.ksks.values());return e?t.filter((n)=>n.hostedZoneId===e):t}getDSRecord(e){let t=this.ksks.get(e);if(!t||!t.dsRecord)throw Error("DS record not available");return t.dsRecord}generatePublicKey(){let t="";for(let n=0;n<256;n++)t+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return t}generateDigest(e){let n="";for(let r=0;r<64;r++)n+="0123456789ABCDEF".charAt(Math.floor(Math.random()*16));return n}generateDNSSECCF(e){return{Type:"AWS::Route53::DNSSEC",Properties:{HostedZoneId:e.hostedZoneId}}}generateKSKCF(e){return{Type:"AWS::Route53::KeySigningKey",Properties:{Name:e.name,HostedZoneId:e.hostedZoneId,KeyManagementServiceArn:e.keyManagementServiceArn,Status:e.status}}}clear(){this.configs.clear(),this.ksks.clear(),this.validations.clear(),this.configCounter=0,this.kskCounter=0,this.validationCounter=0}}var oS=new Fi;class Gi{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(e){let t=`endpoint-${Date.now()}-${this.endpointCounter++}`,n={id:t,status:"CREATING",...e};return this.endpoints.set(t,n),setTimeout(()=>{n.status="OPERATIONAL",n.ipAddresses.forEach((r)=>{if(!r.ip)r.ip=`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`})},100),n}createInboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"INBOUND",ipAddresses:e.subnetIds.map((t)=>({subnetId:t})),securityGroupIds:e.securityGroupIds})}createOutboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"OUTBOUND",ipAddresses:e.subnetIds.map((t)=>({subnetId:t})),securityGroupIds:e.securityGroupIds})}createResolverRule(e){let t=`rule-${Date.now()}-${this.ruleCounter++}`,n={id:t,status:"CREATING",...e};return this.rules.set(t,n),setTimeout(()=>{n.status="COMPLETE"},100),n}createForwardRule(e){return this.createResolverRule({name:e.name,ruleType:"FORWARD",domainName:e.domainName,targetIps:e.targetIps,resolverEndpointId:e.resolverEndpointId})}createSystemRule(e){return this.createResolverRule({name:e.name,ruleType:"SYSTEM",domainName:e.domainName})}createFirewallDomainList(e){let t=`domain-list-${Date.now()}-${this.domainListCounter++}`,n={id:t,status:"CREATING",...e};return this.domainLists.set(t,n),setTimeout(()=>{n.status="COMPLETE"},100),n}createFirewallRuleGroup(e){let t=`rule-group-${Date.now()}-${this.ruleGroupCounter++}`,n={id:t,name:e.name,rules:e.rules.map((r,i)=>({id:`rule-${t}-${i}`,...r})),shareStatus:"NOT_SHARED"};return this.ruleGroups.set(t,n),n}createBlockRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"BLOCK",blockResponse:e.blockResponse||"NODATA",blockOverrideDomain:e.blockOverrideDomain,firewallDomainListId:e.domainListId}]})}createAllowRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"ALLOW",firewallDomainListId:e.domainListId}]})}createDNSFirewall(e){let t=`firewall-${Date.now()}-${this.firewallCounter++}`,n={id:t,name:e.name,firewallRuleGroupAssociations:e.ruleGroupAssociations.map((r,i)=>({id:`assoc-${t}-${i}`,vpcId:e.vpcId,firewallRuleGroupId:r.firewallRuleGroupId,priority:r.priority,mutationProtection:r.mutationProtection||"DISABLED",status:"COMPLETE"}))};return this.firewalls.set(t,n),n}createMalwareProtectionFirewall(e){let t=this.createFirewallDomainList({name:`${e.name}-malware-domains`,domains:e.maliciousDomains}),n=this.createBlockRule({name:`${e.name}-block-malware`,priority:100,domainListId:t.id,blockResponse:"NXDOMAIN"});return this.createDNSFirewall({name:e.name,vpcId:e.vpcId,ruleGroupAssociations:[{firewallRuleGroupId:n.id,priority:100,mutationProtection:"ENABLED"}]})}getEndpoint(e){return this.endpoints.get(e)}listEndpoints(e){let t=Array.from(this.endpoints.values());return e?t.filter((n)=>n.direction===e):t}getRule(e){return this.rules.get(e)}listRules(){return Array.from(this.rules.values())}getFirewall(e){return this.firewalls.get(e)}listFirewalls(){return Array.from(this.firewalls.values())}generateResolverEndpointCF(e){return{Type:"AWS::Route53Resolver::ResolverEndpoint",Properties:{Name:e.name,Direction:e.direction,IpAddresses:e.ipAddresses.map((t)=>({SubnetId:t.subnetId,...t.ip&&{Ip:t.ip}})),SecurityGroupIds:e.securityGroupIds}}}generateResolverRuleCF(e){return{Type:"AWS::Route53Resolver::ResolverRule",Properties:{Name:e.name,RuleType:e.ruleType,DomainName:e.domainName,...e.targetIps&&{TargetIps:e.targetIps.map((t)=>({Ip:t.ip,Port:t.port||53}))},...e.resolverEndpointId&&{ResolverEndpointId:e.resolverEndpointId}}}}generateFirewallRuleGroupCF(e){return{Type:"AWS::Route53Resolver::FirewallRuleGroup",Properties:{Name:e.name,FirewallRules:e.rules.map((t)=>({Name:t.name,Priority:t.priority,Action:t.action,FirewallDomainListId:t.firewallDomainListId,...t.blockResponse&&{BlockResponse:t.blockResponse},...t.blockOverrideDomain&&{BlockOverrideDomain:t.blockOverrideDomain},...t.blockOverrideTTL&&{BlockOverrideTtl:t.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 lS=new Gi;class _i{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(e){let t=`bounce-${Date.now()}-${this.bounceCounter++}`,n={id:t,...e};if(this.bounces.set(t,n),e.bounceType==="Permanent")this.addToSuppressionList({emailAddress:e.recipient,reason:"BOUNCE"});return n}recordComplaint(e){let t=`complaint-${Date.now()}-${this.complaintCounter++}`,n={id:t,...e};this.complaints.set(t,n);for(let r of e.recipients)this.addToSuppressionList({emailAddress:r,reason:"COMPLAINT"});return n}createBounceHandler(e){let t=`handler-${Date.now()}-${this.handlerCounter++}`,n={id:t,...e};return this.handlers.set(t,n),n}createAutomaticBounceHandler(e){return this.createBounceHandler({name:e.name,bounceThreshold:5,complaintThreshold:0.1,suppressionDuration:2592000,autoSuppress:!0,notificationTopicArn:e.notificationTopicArn})}addToSuppressionList(e){let t=`suppression-${Date.now()}-${this.suppressionCounter++}`,n=e.expirationDays?new Date(Date.now()+e.expirationDays*24*60*60*1000):void 0,r={id:t,emailAddress:e.emailAddress,reason:e.reason,suppressedAt:new Date,expiresAt:n,bounceCount:e.reason==="BOUNCE"?1:0,complaintCount:e.reason==="COMPLAINT"?1:0};return this.suppressionList.set(e.emailAddress,r),r}removeFromSuppressionList(e){return this.suppressionList.delete(e)}isSuppressed(e){let t=this.suppressionList.get(e);if(!t)return!1;if(t.expiresAt&&t.expiresAt<new Date)return this.suppressionList.delete(e),!1;return!0}getBounceStatistics(e,t){let n=Array.from(this.bounces.values()).filter((u)=>u.timestamp>=e&&u.timestamp<=t),r=n.length,i=n.filter((u)=>u.bounceType==="Permanent").length,s=n.filter((u)=>u.bounceType==="Transient").length,a=r*10,o=r/a*100,c=new Map;for(let u of n)c.set(u.recipient,(c.get(u.recipient)||0)+1);let l=Array.from(c.entries()).map(([u,m])=>({email:u,count:m})).sort((u,m)=>m.count-u.count).slice(0,10);return{totalBounces:r,permanentBounces:i,transientBounces:s,bounceRate:o,topRecipients:l}}getComplaintStatistics(e,t){let n=Array.from(this.complaints.values()).filter((c)=>c.timestamp>=e&&c.timestamp<=t),r=n.length,i=new Set;for(let c of n)for(let l of c.recipients)i.add(l);let s=i.size,a=r*1000,o=r/a*100;return{totalComplaints:r,uniqueComplainters:s,complaintRate:o}}calculateReputationMetrics(){let e=`metrics-${Date.now()}-${this.metricsCounter++}`,t=new Date,n=new Date(t.getTime()-86400000),r=this.getBounceStatistics(n,t),i=this.getComplaintStatistics(n,t),s;if(r.bounceRate>10||i.complaintRate>0.5)s="Shutdown";else if(r.bounceRate>5||i.complaintRate>0.1)s="Probation";else if(r.bounceRate>2||i.complaintRate>0.05)s="Warning";else s="Good";let a={id:e,timestamp:t,bounceRate:r.bounceRate,complaintRate:i.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:r.totalBounces*10,reputationStatus:s};return this.metrics.set(e,a),a}getBounces(e){let t=Array.from(this.bounces.values());return e?t.filter((n)=>n.messageId===e):t}getComplaints(e){let t=Array.from(this.complaints.values());return e?t.filter((n)=>n.messageId===e):t}listSuppressionList(e){let t=Array.from(this.suppressionList.values());return e?t.filter((n)=>n.reason===e):t}generateSNSSubscriptionCF(e){return{Type:"AWS::SNS::Subscription",Properties:{TopicArn:e.topicArn,Endpoint:e.endpoint,Protocol:e.protocol}}}generateEventDestinationCF(e){return{Type:"AWS::SES::ConfigurationSetEventDestination",Properties:{ConfigurationSetName:e.configurationSetName,EventDestination:{Name:e.eventDestinationName,Enabled:!0,MatchingEventTypes:e.eventTypes,...e.snsTopicArn&&{SnsDestination:{TopicARN:e.snsTopicArn}},...e.cloudWatchDestination&&{CloudWatchDestination:e.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 dS=new _i;class Wi{events=new Map;campaigns=new Map;reports=new Map;abTests=new Map;eventCounter=0;campaignCounter=0;reportCounter=0;abTestCounter=0;trackEvent(e){let t=`event-${Date.now()}-${this.eventCounter++}`,n={id:t,...e};if(this.events.set(t,n),e.tags?.campaignId)this.updateCampaignStats(e.tags.campaignId,e.eventType);return n}trackOpen(e){return this.trackEvent({...e,eventType:"open",timestamp:new Date})}trackClick(e){return this.trackEvent({...e,eventType:"click",timestamp:new Date})}createCampaign(e){let t=`campaign-${Date.now()}-${this.campaignCounter++}`,n={id:t,sentCount:0,deliveredCount:0,openCount:0,clickCount:0,bounceCount:0,complaintCount:0,createdAt:new Date,...e};return this.campaigns.set(t,n),n}updateCampaignStats(e,t){let n=this.campaigns.get(e);if(!n)return;switch(t){case"send":n.sentCount++;break;case"delivery":n.deliveredCount++;break;case"open":n.openCount++;break;case"click":n.clickCount++;break;case"bounce":n.bounceCount++;break;case"complaint":n.complaintCount++;break}}generateReport(e){let t=`report-${Date.now()}-${this.reportCounter++}`,n=Array.from(this.events.values()).filter((A)=>{let R=A.timestamp>=e.startDate&&A.timestamp<=e.endDate,P=!e.campaignId||A.tags?.campaignId===e.campaignId;return R&&P}),r=n.filter((A)=>A.eventType==="send").length,i=n.filter((A)=>A.eventType==="delivery").length,s=n.filter((A)=>A.eventType==="open").length,a=n.filter((A)=>A.eventType==="click").length,o=n.filter((A)=>A.eventType==="bounce").length,c=n.filter((A)=>A.eventType==="complaint").length,l=r>0?i/r*100:0,u=i>0?s/i*100:0,m=i>0?a/i*100:0,p=s>0?a/s*100:0,g=r>0?o/r*100:0,y=i>0?c/i*100:0,h=new Map;for(let A of n)if(A.eventType==="click"){let R=A;h.set(R.link,(h.get(R.link)||0)+1)}let b=Array.from(h.entries()).map(([A,R])=>({link:A,clicks:R})).sort((A,R)=>R.clicks-A.clicks).slice(0,10),C={desktop:0,mobile:0,tablet:0,unknown:0};for(let A of n)if(A.eventType==="open"||A.eventType==="click"){let R=A.userAgent.toLowerCase();if(R.includes("mobile"))C.mobile++;else if(R.includes("tablet"))C.tablet++;else if(R.includes("mozilla"))C.desktop++;else C.unknown++}let T={id:t,campaignId:e.campaignId,startDate:e.startDate,endDate:e.endDate,totalSent:r,totalDelivered:i,totalOpened:s,totalClicked:a,totalBounced:o,totalComplaints:c,deliveryRate:l,openRate:u,clickRate:m,clickToOpenRate:p,bounceRate:g,complaintRate:y,topLinks:b,deviceBreakdown:C,locationBreakdown:{}};return this.reports.set(t,T),T}createABTest(e){let t=`abtest-${Date.now()}-${this.abTestCounter++}`,n={id:t,name:e.name,variants:e.variants.map((r,i)=>({id:`variant-${t}-${i}`,sentCount:0,openCount:0,clickCount:0,conversionCount:0,...r})),status:"draft"};return this.abTests.set(t,n),n}startABTest(e){let t=this.abTests.get(e);if(!t)throw Error(`A/B test not found: ${e}`);return t.status="running",t.startedAt=new Date,t}completeABTest(e){let t=this.abTests.get(e);if(!t)throw Error(`A/B test not found: ${e}`);let n=t.variants[0],r=0;for(let i of t.variants){let s=i.sentCount>0?i.openCount/i.sentCount:0;if(s>r)r=s,n=i}return t.status="completed",t.completedAt=new Date,t.winner=n.id,t}getCampaign(e){return this.campaigns.get(e)}listCampaigns(){return Array.from(this.campaigns.values())}getEvents(e){let t=Array.from(this.events.values());if(e?.messageId)t=t.filter((n)=>n.messageId===e.messageId);if(e?.eventType)t=t.filter((n)=>n.eventType===e.eventType);if(e?.startDate)t=t.filter((n)=>n.timestamp>=e.startDate);if(e?.endDate)t=t.filter((n)=>n.timestamp<=e.endDate);return t}generateTrackingConfigurationCF(e){return{Type:"AWS::SES::ConfigurationSet",Properties:{Name:e.configurationSetName,...e.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 pS=new Wi;class Vi{dashboards=new Map;warmupPlans=new Map;domainReputations=new Map;dashboardCounter=0;warmupCounter=0;domainCounter=0;getReputationDashboard(){let e=`dashboard-${Date.now()}-${this.dashboardCounter++}`,t=Math.random()*5,n=Math.random()*0.5,r=Math.floor(Math.random()*10),i=Math.max(0,100-t*10-n*100-r*2),s=[];if(t>2)s.push("Reduce bounce rate by cleaning email list");if(n>0.1)s.push("Review email content and unsubscribe process");if(r>5)s.push("Improve email relevance and targeting");let a={id:e,timestamp:new Date,overallScore:i,bounceRate:t,complaintRate:n,spamReports:r,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:s};return this.dashboards.set(e,a),a}checkBlacklists(){return["Spamhaus ZEN","Spamcop","SORBS","Barracuda","URIBL"].map((t)=>({listName:t,listed:Math.random()>0.95,delistUrl:`https://www.${t.toLowerCase().replace(/\s/g,"")}.org/delist`}))}createWarmupPlan(e){let t=`warmup-${Date.now()}-${this.warmupCounter++}`,n=[],r=(e.targetDailyLimit-e.initialDailyLimit)/e.durationDays;for(let s=0;s<e.durationDays;s++)n.push(Math.floor(e.initialDailyLimit+r*s));let i={id:t,name:e.name,startDate:new Date,currentDay:1,totalDays:e.durationDays,dailyLimits:n,currentLimit:n[0],status:"active"};return this.warmupPlans.set(t,i),i}createAggressiveWarmupPlan(e){return this.createWarmupPlan({name:e.name,initialDailyLimit:500,targetDailyLimit:50000,durationDays:14})}createConservativeWarmupPlan(e){return this.createWarmupPlan({name:e.name,initialDailyLimit:200,targetDailyLimit:50000,durationDays:30})}advanceWarmupPlan(e){let t=this.warmupPlans.get(e);if(!t)throw Error(`Warmup plan not found: ${e}`);if(t.currentDay<t.totalDays)t.currentDay++,t.currentLimit=t.dailyLimits[t.currentDay-1];if(t.currentDay>=t.totalDays)t.status="completed";return t}trackDomainReputation(e){let t=`domain-${Date.now()}-${this.domainCounter++}`,n=e.delivered/e.totalSent*100,r=e.delivered>0?e.opened/e.delivered*100:0,i=e.delivered>0?e.clicked/e.delivered*100:0,s=e.bounced/e.totalSent*100,a=e.delivered>0?e.complained/e.delivered*100:0,o=r*0.4+i*0.6,c=Math.max(0,100-s*10-a*100+o*0.2),l={id:t,domain:e.domain,reputationScore:c,totalSent:e.totalSent,deliveryRate:n,openRate:r,clickRate:i,bounceRate:s,complaintRate:a,engagementScore:o};return this.domainReputations.set(e.domain,l),l}getDomainReputation(e){return this.domainReputations.get(e)}listDomainReputations(){return Array.from(this.domainReputations.values())}getWarmupPlan(e){return this.warmupPlans.get(e)}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 yS=new Vi;class Ui{templates=new Map;versions=new Map;tests=new Map;templateCounter=0;testCounter=0;createTemplate(e){let t=`template-${Date.now()}-${this.templateCounter++}`,n=this.extractVariables(e.subject+e.htmlPart+e.textPart),r={id:t,variables:n,createdAt:new Date,updatedAt:new Date,version:1,...e};return this.templates.set(t,r),this.addVersion({templateId:t,version:1,subject:e.subject,htmlPart:e.htmlPart,textPart:e.textPart,createdBy:"system"}),r}createWelcomeTemplate(e){return this.createTemplate({name:e.name,subject:"Welcome to {{companyName}}!",htmlPart:`
3764
3764
  <html>
3765
3765
  <body>
3766
3766
  <h1>Welcome, {{userName}}!</h1>
@@ -4149,7 +4149,7 @@ else {
4149
4149
 
4150
4150
  return raw;
4151
4151
  }
4152
- `;static createSchedulerLambda(e){return{[`${e.slug}EmailSchedulerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:300,MemorySize:256,Code:{ZipFile:xn.SchedulerLambdaCode},Environment:{Variables:{EMAIL_BUCKET:e.emailBucket}}}}}}static createSchedulerRule(e){return{[`${e.slug}EmailSchedulerRule`]:{Type:"AWS::Events::Rule",Properties:{Name:`${e.slug}-email-scheduler`,Description:"Trigger email scheduler every minute",ScheduleExpression:e.scheduleExpression||"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:e.lambdaArn}]}},[`${e.slug}EmailSchedulerPermission`]:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:e.lambdaArn,Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:{"Fn::GetAtt":[`${e.slug}EmailSchedulerRule`,"Arn"]}}}}}static async scheduleEmail(e){let{s3Client:t,bucket:n,email:r,scheduledFor:i,timezone:s}=e,a=`sched-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,o={id:a,email:r,scheduledFor:typeof i==="string"?i:i.toISOString(),timezone:s,status:"pending",createdAt:new Date().toISOString()};return await t.send({Bucket:n,Key:`scheduled/${a}.json`,Body:JSON.stringify(o,null,2),ContentType:"application/json"}),o}static async cancelScheduledEmail(e){let{s3Client:t,bucket:n,id:r}=e;try{let i=await t.send({Bucket:n,Key:`scheduled/${r}.json`}),s=JSON.parse(i.Body);if(s.status!=="pending")return!1;return s.status="cancelled",await t.send({Bucket:n,Key:`scheduled/${r}.json`,Body:JSON.stringify(s,null,2),ContentType:"application/json"}),!0}catch{return!1}}static async listScheduledEmails(e){let{s3Client:t,bucket:n,status:r}=e,i=await t.send({Bucket:n,Prefix:"scheduled/"}),s=[];for(let a of i.Contents||[]){if(!a.Key.endsWith(".json"))continue;try{let o=await t.send({Bucket:n,Key:a.Key}),c=JSON.parse(o.Body);if(!r||c.status===r)s.push(c)}catch{}}return s.sort((a,o)=>new Date(a.scheduledFor).getTime()-new Date(o.scheduledFor).getTime()),s}}class pt{static TrackingPixelLambdaCode=`
4152
+ `;static createSchedulerLambda(e){return{[`${e.slug}EmailSchedulerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:300,MemorySize:256,Code:{ZipFile:xn.SchedulerLambdaCode},Environment:{Variables:{EMAIL_BUCKET:e.emailBucket}}}}}}static createSchedulerRule(e){return{[`${e.slug}EmailSchedulerRule`]:{Type:"AWS::Events::Rule",Properties:{Name:`${e.slug}-email-scheduler`,Description:"Trigger email scheduler every minute",ScheduleExpression:e.scheduleExpression||"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:e.lambdaArn}]}},[`${e.slug}EmailSchedulerPermission`]:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:e.lambdaArn,Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:{"Fn::GetAtt":[`${e.slug}EmailSchedulerRule`,"Arn"]}}}}}static async scheduleEmail(e){let{s3Client:t,bucket:n,email:r,scheduledFor:i,timezone:s}=e,a=`sched-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,o={id:a,email:r,scheduledFor:typeof i==="string"?i:i.toISOString(),timezone:s,status:"pending",createdAt:new Date().toISOString()};return await t.send({Bucket:n,Key:`scheduled/${a}.json`,Body:JSON.stringify(o,null,2),ContentType:"application/json"}),o}static async cancelScheduledEmail(e){let{s3Client:t,bucket:n,id:r}=e;try{let i=await t.send({Bucket:n,Key:`scheduled/${r}.json`}),s=JSON.parse(i.Body);if(s.status!=="pending")return!1;return s.status="cancelled",await t.send({Bucket:n,Key:`scheduled/${r}.json`,Body:JSON.stringify(s,null,2),ContentType:"application/json"}),!0}catch{return!1}}static async listScheduledEmails(e){let{s3Client:t,bucket:n,status:r}=e,i=await t.send({Bucket:n,Prefix:"scheduled/"}),s=[];for(let a of i.Contents||[]){if(!a.Key.endsWith(".json"))continue;try{let o=await t.send({Bucket:n,Key:a.Key}),c=JSON.parse(o.Body);if(!r||c.status===r)s.push(c)}catch{}}return s.sort((a,o)=>new Date(a.scheduledFor).getTime()-new Date(o.scheduledFor).getTime()),s}}class gt{static TrackingPixelLambdaCode=`
4153
4153
  const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
4154
4154
 
4155
4155
  const dynamodb = new DynamoDBClient({});
@@ -4352,7 +4352,7 @@ catch (error) {
4352
4352
 
4353
4353
  return { statusCode: 200 };
4354
4354
  };
4355
- `;static createAnalyticsTable(e){return{[`${e.slug}EmailAnalyticsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createTrackingPixelLambda(e){return{[`${e.slug}TrackingPixelLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-tracking-pixel`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:pt.TrackingPixelLambdaCode},Environment:{Variables:{ANALYTICS_TABLE:e.analyticsTable}}}}}}static createClickTrackingLambda(e){return{[`${e.slug}ClickTrackingLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-click-tracking`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:pt.ClickTrackingLambdaCode},Environment:{Variables:{ANALYTICS_TABLE:e.analyticsTable}}}}}}static createSesEventProcessorLambda(e){return{[`${e.slug}SesEventProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-ses-event-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:pt.SesEventProcessorCode},Environment:{Variables:{ANALYTICS_TABLE:e.analyticsTable}}}}}}static injectTracking(e){let{html:t,messageId:n,trackingDomain:r}=e,i=`<img src="https://${r}/track/open/${n}" width="1" height="1" style="display:none" alt="" />`,s=t.replace("</body>",`${i}</body>`);return s=s.replace(/href="(https?:\/\/[^"]+)"/g,(a,o)=>{let c=encodeURIComponent(o);return`href="https://${r}/track/click/${n}?url=${c}"`}),s}static calculateMetrics(e){let t=e.filter((c)=>c.sent).length,n=e.filter((c)=>c.delivered).length,r=e.filter((c)=>c.opened).length,i=e.filter((c)=>c.clicked).length,s=e.filter((c)=>c.bounced).length,a=e.filter((c)=>c.complained).length,o=e.filter((c)=>c.unsubscribed).length;return{period:new Date().toISOString(),sent:t,delivered:n,opened:r,clicked:i,bounced:s,complained:a,unsubscribed:o,deliveryRate:t>0?n/t*100:0,openRate:n>0?r/n*100:0,clickRate:r>0?i/r*100:0,bounceRate:t>0?s/t*100:0,complaintRate:n>0?a/n*100:0}}}class ke{static TemplateRendererCode=`
4355
+ `;static createAnalyticsTable(e){return{[`${e.slug}EmailAnalyticsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createTrackingPixelLambda(e){return{[`${e.slug}TrackingPixelLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-tracking-pixel`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:gt.TrackingPixelLambdaCode},Environment:{Variables:{ANALYTICS_TABLE:e.analyticsTable}}}}}}static createClickTrackingLambda(e){return{[`${e.slug}ClickTrackingLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-click-tracking`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:gt.ClickTrackingLambdaCode},Environment:{Variables:{ANALYTICS_TABLE:e.analyticsTable}}}}}}static createSesEventProcessorLambda(e){return{[`${e.slug}SesEventProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-ses-event-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:gt.SesEventProcessorCode},Environment:{Variables:{ANALYTICS_TABLE:e.analyticsTable}}}}}}static injectTracking(e){let{html:t,messageId:n,trackingDomain:r}=e,i=`<img src="https://${r}/track/open/${n}" width="1" height="1" style="display:none" alt="" />`,s=t.replace("</body>",`${i}</body>`);return s=s.replace(/href="(https?:\/\/[^"]+)"/g,(a,o)=>{let c=encodeURIComponent(o);return`href="https://${r}/track/click/${n}?url=${c}"`}),s}static calculateMetrics(e){let t=e.filter((c)=>c.sent).length,n=e.filter((c)=>c.delivered).length,r=e.filter((c)=>c.opened).length,i=e.filter((c)=>c.clicked).length,s=e.filter((c)=>c.bounced).length,a=e.filter((c)=>c.complained).length,o=e.filter((c)=>c.unsubscribed).length;return{period:new Date().toISOString(),sent:t,delivered:n,opened:r,clicked:i,bounced:s,complained:a,unsubscribed:o,deliveryRate:t>0?n/t*100:0,openRate:n>0?r/n*100:0,clickRate:r>0?i/r*100:0,bounceRate:t>0?s/t*100:0,complaintRate:n>0?a/n*100:0}}}class Me{static TemplateRendererCode=`
4356
4356
  const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
4357
4357
 
4358
4358
  const s3 = new S3Client({});
@@ -4607,7 +4607,7 @@ The {{appName}} Team`,variables:["appName","userName","resetUrl","expiresIn"],ca
4607
4607
 
4608
4608
  <p>Best regards,<br>The {{appName}} Team</p>
4609
4609
  </body>
4610
- </html>`,variables:["invoiceNumber","customerName","period","items","total","paymentUrl","appName"],category:"billing"}};static createTemplateBucket(e){return{[`${e.slug}EmailTemplateBucket`]:{Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-email-templates`,VersioningConfiguration:{Status:"Enabled"}}}}}static createTemplateRendererLambda(e){return{[`${e.slug}TemplateRendererLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-template-renderer`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:ke.TemplateRendererCode},Environment:{Variables:{TEMPLATE_BUCKET:e.templateBucket}}}}}}static render(e,t){if(!e||!t)return e;let n=e;return n=n.replace(/\{\{\s*([\w.]+)\s*\}\}/g,(r,i)=>{let s=ke.getNestedValue(t,i);return s!==void 0?String(s):r}),n=n.replace(/\{\{#if\s+([\w.]+)\}\}([\s\S]*?)\{\{\/if\}\}/g,(r,i,s)=>ke.getNestedValue(t,i)?s:""),n=n.replace(/\{\{#unless\s+([\w.]+)\}\}([\s\S]*?)\{\{\/unless\}\}/g,(r,i,s)=>!ke.getNestedValue(t,i)?s:""),n=n.replace(/\{\{#each\s+([\w.]+)\}\}([\s\S]*?)\{\{\/each\}\}/g,(r,i,s)=>{let a=ke.getNestedValue(t,i);if(!Array.isArray(a))return"";return a.map((o,c)=>{let l=s;if(l=l.replace(/\{\{this\}\}/g,String(o)),l=l.replace(/\{\{@index\}\}/g,String(c)),typeof o==="object")Object.entries(o).forEach(([u,m])=>{l=l.replace(new RegExp(`\\{\\{\\s*${u}\\s*\\}\\}`,"g"),String(m))});return l}).join("")}),n}static getNestedValue(e,t){return t.split(".").reduce((n,r)=>n?.[r],e)}static extractVariables(e){let t=new Set,n=e.matchAll(/\{\{\s*([\w.]+)\s*\}\}/g);for(let i of n)if(!i[1].startsWith("#")&&!i[1].startsWith("/")&&!i[1].startsWith("@"))t.add(i[1].split(".")[0]);let r=e.matchAll(/\{\{#(?:if|unless|each)\s+([\w.]+)\}\}/g);for(let i of r)t.add(i[1].split(".")[0]);return Array.from(t)}}class kn{static SharedMailboxLambdaCode=`
4610
+ </html>`,variables:["invoiceNumber","customerName","period","items","total","paymentUrl","appName"],category:"billing"}};static createTemplateBucket(e){return{[`${e.slug}EmailTemplateBucket`]:{Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-email-templates`,VersioningConfiguration:{Status:"Enabled"}}}}}static createTemplateRendererLambda(e){return{[`${e.slug}TemplateRendererLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-template-renderer`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Me.TemplateRendererCode},Environment:{Variables:{TEMPLATE_BUCKET:e.templateBucket}}}}}}static render(e,t){if(!e||!t)return e;let n=e;return n=n.replace(/\{\{\s*([\w.]+)\s*\}\}/g,(r,i)=>{let s=Me.getNestedValue(t,i);return s!==void 0?String(s):r}),n=n.replace(/\{\{#if\s+([\w.]+)\}\}([\s\S]*?)\{\{\/if\}\}/g,(r,i,s)=>Me.getNestedValue(t,i)?s:""),n=n.replace(/\{\{#unless\s+([\w.]+)\}\}([\s\S]*?)\{\{\/unless\}\}/g,(r,i,s)=>!Me.getNestedValue(t,i)?s:""),n=n.replace(/\{\{#each\s+([\w.]+)\}\}([\s\S]*?)\{\{\/each\}\}/g,(r,i,s)=>{let a=Me.getNestedValue(t,i);if(!Array.isArray(a))return"";return a.map((o,c)=>{let l=s;if(l=l.replace(/\{\{this\}\}/g,String(o)),l=l.replace(/\{\{@index\}\}/g,String(c)),typeof o==="object")Object.entries(o).forEach(([u,m])=>{l=l.replace(new RegExp(`\\{\\{\\s*${u}\\s*\\}\\}`,"g"),String(m))});return l}).join("")}),n}static getNestedValue(e,t){return t.split(".").reduce((n,r)=>n?.[r],e)}static extractVariables(e){let t=new Set,n=e.matchAll(/\{\{\s*([\w.]+)\s*\}\}/g);for(let i of n)if(!i[1].startsWith("#")&&!i[1].startsWith("/")&&!i[1].startsWith("@"))t.add(i[1].split(".")[0]);let r=e.matchAll(/\{\{#(?:if|unless|each)\s+([\w.]+)\}\}/g);for(let i of r)t.add(i[1].split(".")[0]);return Array.from(t)}}class kn{static SharedMailboxLambdaCode=`
4611
4611
  const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
4612
4612
  const { DynamoDBClient, GetItemCommand, PutItemCommand, QueryCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
4613
4613
 
@@ -5659,7 +5659,7 @@ else if (jobStatus === 'FAILED') {
5659
5659
 
5660
5660
  return { statusCode: 200 };
5661
5661
  };
5662
- `;static createRecordingsTable(e){return{[`${e.slug}CallRecordingsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"},{AttributeName:"transcriptionJobName",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"job-index",KeySchema:[{AttributeName:"transcriptionJobName",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createRecordingProcessorLambda(e){return{[`${e.slug}RecordingProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-recording-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:Ln.RecordingProcessorCode},Environment:{Variables:{RECORDING_BUCKET:e.recordingBucket,RECORDINGS_TABLE:e.recordingsTable}}}}}}}class He{nodes=[];connections=[];startNodeId="";static create(e){return new He}start(){let e={id:this.generateId(),type:"start",position:{x:0,y:0},config:{}};return this.nodes.push(e),this.startNodeId=e.id,this}playPrompt(e,t){let n={id:this.generateId(),type:"play-prompt",position:{x:0,y:0},config:{text:e,textType:t?.ssml?"ssml":"text",voice:t?.voice||"Joanna"}};return this.nodes.push(n),this.connectToLast(n.id),this}getInput(e,t){let n={id:this.generateId(),type:"get-input",position:{x:0,y:0},config:{prompt:e,maxDigits:t?.maxDigits||1,timeout:t?.timeout||5,errorPrompt:t?.errorPrompt||"Sorry, I didn't get that."}};return this.nodes.push(n),this.connectToLast(n.id),this}menu(e,t){let n={id:this.generateId(),type:"menu",position:{x:0,y:0},config:{prompt:e,options:t}};return this.nodes.push(n),this.connectToLast(n.id),this}transferToQueue(e,t){let n={id:this.generateId(),type:"transfer-queue",position:{x:0,y:0},config:{queueArn:e,priority:t?.priority||5}};return this.nodes.push(n),this.connectToLast(n.id),this}transferToPhone(e){let t={id:this.generateId(),type:"transfer-phone",position:{x:0,y:0},config:{phoneNumber:e}};return this.nodes.push(t),this.connectToLast(t.id),this}invokeLambda(e,t){let n={id:this.generateId(),type:"invoke-lambda",position:{x:0,y:0},config:{functionArn:e,timeout:t?.timeout||8}};return this.nodes.push(n),this.connectToLast(n.id),this}setAttribute(e,t){let n={id:this.generateId(),type:"set-attribute",position:{x:0,y:0},config:{key:e,value:t}};return this.nodes.push(n),this.connectToLast(n.id),this}checkHours(e){let t={id:this.generateId(),type:"check-hours",position:{x:0,y:0},config:{hoursOfOperationArn:e}};return this.nodes.push(t),this.connectToLast(t.id),this}recordVoicemail(e){let t={id:this.generateId(),type:"record-voicemail",position:{x:0,y:0},config:{maxDuration:e?.maxDuration||120,greeting:e?.greeting||"Please leave a message after the beep.",beep:e?.beep!==!1}};return this.nodes.push(t),this.connectToLast(t.id),this}wait(e){let t={id:this.generateId(),type:"wait",position:{x:0,y:0},config:{seconds:e}};return this.nodes.push(t),this.connectToLast(t.id),this}disconnect(){let e={id:this.generateId(),type:"disconnect",position:{x:0,y:0},config:{}};return this.nodes.push(e),this.connectToLast(e.id),this}build(){return{id:this.generateId(),name:"IVR Flow",nodes:this.nodes,connections:this.connections,startNodeId:this.startNodeId,version:1,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}}toContactFlow(){let e=[],t=new Map(this.nodes.map((r)=>[r.id,r]));for(let r of this.nodes){let i=this.nodeToAction(r,t);if(i)e.push(i)}let n={Version:"2019-10-30",StartAction:this.startNodeId,Actions:e};return JSON.stringify(n,null,2)}nodeToAction(e,t){let n=this.getNextNodeId(e.id),r={NextAction:n||"disconnect",Errors:[{NextAction:"disconnect"}]};switch(e.type){case"start":return null;case"play-prompt":return{Identifier:e.id,Type:"MessageParticipant",Parameters:{Text:e.config.text,TextType:e.config.textType},Transitions:r};case"get-input":return{Identifier:e.id,Type:"GetParticipantInput",Parameters:{Text:e.config.prompt,InputTimeLimitSeconds:e.config.timeout,MaxDigits:e.config.maxDigits},Transitions:{...r,Conditions:[]}};case"transfer-queue":return{Identifier:e.id,Type:"TransferToQueue",Parameters:{QueueId:e.config.queueArn},Transitions:r};case"transfer-phone":return{Identifier:e.id,Type:"TransferToPhoneNumber",Parameters:{PhoneNumber:e.config.phoneNumber},Transitions:r};case"invoke-lambda":return{Identifier:e.id,Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:e.config.functionArn,InvocationTimeLimitSeconds:e.config.timeout},Transitions:r};case"set-attribute":return{Identifier:e.id,Type:"UpdateContactAttributes",Parameters:{Attributes:{[e.config.key]:e.config.value}},Transitions:r};case"check-hours":return{Identifier:e.id,Type:"CheckHoursOfOperation",Parameters:{HoursOfOperationId:e.config.hoursOfOperationArn},Transitions:{NextAction:n,Conditions:[{NextAction:n,Condition:{Operator:"Equals",Operands:["True"]}}],Errors:[{NextAction:"disconnect"}]}};case"wait":return{Identifier:e.id,Type:"Wait",Parameters:{Seconds:e.config.seconds},Transitions:r};case"disconnect":return{Identifier:e.id,Type:"DisconnectParticipant",Parameters:{},Transitions:{}};default:return null}}connectToLast(e){if(this.nodes.length>1){let t=this.nodes[this.nodes.length-2];this.connections.push({id:this.generateId(),sourceNodeId:t.id,targetNodeId:e,sourcePort:"default"})}}getNextNodeId(e){return this.connections.find((n)=>n.sourceNodeId===e)?.targetNodeId||null}generateId(){return`node-${Date.now()}-${Math.random().toString(36).substr(2,9)}`}static Templates={basicSupport:()=>He.create("Basic Support").start().playPrompt("Welcome to customer support.").menu("Press 1 for sales, 2 for support, or 3 to leave a message.",{"1":"sales","2":"support","3":"voicemail"}),afterHours:(e)=>He.create("After Hours").start().playPrompt(e).recordVoicemail({greeting:"Please leave your name, number, and a brief message.",maxDuration:120}).playPrompt("Thank you for your message. Goodbye.").disconnect(),callbackRequest:(e)=>He.create("Callback Request").start().playPrompt("All agents are currently busy.").getInput("Press 1 to request a callback, or 2 to wait.",{maxDigits:1}).invokeLambda(e).playPrompt("We will call you back shortly. Goodbye.").disconnect()}}class On{static MetricsAggregatorCode=`
5662
+ `;static createRecordingsTable(e){return{[`${e.slug}CallRecordingsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"},{AttributeName:"transcriptionJobName",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"job-index",KeySchema:[{AttributeName:"transcriptionJobName",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createRecordingProcessorLambda(e){return{[`${e.slug}RecordingProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-recording-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:Ln.RecordingProcessorCode},Environment:{Variables:{RECORDING_BUCKET:e.recordingBucket,RECORDINGS_TABLE:e.recordingsTable}}}}}}}class Ke{nodes=[];connections=[];startNodeId="";static create(e){return new Ke}start(){let e={id:this.generateId(),type:"start",position:{x:0,y:0},config:{}};return this.nodes.push(e),this.startNodeId=e.id,this}playPrompt(e,t){let n={id:this.generateId(),type:"play-prompt",position:{x:0,y:0},config:{text:e,textType:t?.ssml?"ssml":"text",voice:t?.voice||"Joanna"}};return this.nodes.push(n),this.connectToLast(n.id),this}getInput(e,t){let n={id:this.generateId(),type:"get-input",position:{x:0,y:0},config:{prompt:e,maxDigits:t?.maxDigits||1,timeout:t?.timeout||5,errorPrompt:t?.errorPrompt||"Sorry, I didn't get that."}};return this.nodes.push(n),this.connectToLast(n.id),this}menu(e,t){let n={id:this.generateId(),type:"menu",position:{x:0,y:0},config:{prompt:e,options:t}};return this.nodes.push(n),this.connectToLast(n.id),this}transferToQueue(e,t){let n={id:this.generateId(),type:"transfer-queue",position:{x:0,y:0},config:{queueArn:e,priority:t?.priority||5}};return this.nodes.push(n),this.connectToLast(n.id),this}transferToPhone(e){let t={id:this.generateId(),type:"transfer-phone",position:{x:0,y:0},config:{phoneNumber:e}};return this.nodes.push(t),this.connectToLast(t.id),this}invokeLambda(e,t){let n={id:this.generateId(),type:"invoke-lambda",position:{x:0,y:0},config:{functionArn:e,timeout:t?.timeout||8}};return this.nodes.push(n),this.connectToLast(n.id),this}setAttribute(e,t){let n={id:this.generateId(),type:"set-attribute",position:{x:0,y:0},config:{key:e,value:t}};return this.nodes.push(n),this.connectToLast(n.id),this}checkHours(e){let t={id:this.generateId(),type:"check-hours",position:{x:0,y:0},config:{hoursOfOperationArn:e}};return this.nodes.push(t),this.connectToLast(t.id),this}recordVoicemail(e){let t={id:this.generateId(),type:"record-voicemail",position:{x:0,y:0},config:{maxDuration:e?.maxDuration||120,greeting:e?.greeting||"Please leave a message after the beep.",beep:e?.beep!==!1}};return this.nodes.push(t),this.connectToLast(t.id),this}wait(e){let t={id:this.generateId(),type:"wait",position:{x:0,y:0},config:{seconds:e}};return this.nodes.push(t),this.connectToLast(t.id),this}disconnect(){let e={id:this.generateId(),type:"disconnect",position:{x:0,y:0},config:{}};return this.nodes.push(e),this.connectToLast(e.id),this}build(){return{id:this.generateId(),name:"IVR Flow",nodes:this.nodes,connections:this.connections,startNodeId:this.startNodeId,version:1,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}}toContactFlow(){let e=[],t=new Map(this.nodes.map((r)=>[r.id,r]));for(let r of this.nodes){let i=this.nodeToAction(r,t);if(i)e.push(i)}let n={Version:"2019-10-30",StartAction:this.startNodeId,Actions:e};return JSON.stringify(n,null,2)}nodeToAction(e,t){let n=this.getNextNodeId(e.id),r={NextAction:n||"disconnect",Errors:[{NextAction:"disconnect"}]};switch(e.type){case"start":return null;case"play-prompt":return{Identifier:e.id,Type:"MessageParticipant",Parameters:{Text:e.config.text,TextType:e.config.textType},Transitions:r};case"get-input":return{Identifier:e.id,Type:"GetParticipantInput",Parameters:{Text:e.config.prompt,InputTimeLimitSeconds:e.config.timeout,MaxDigits:e.config.maxDigits},Transitions:{...r,Conditions:[]}};case"transfer-queue":return{Identifier:e.id,Type:"TransferToQueue",Parameters:{QueueId:e.config.queueArn},Transitions:r};case"transfer-phone":return{Identifier:e.id,Type:"TransferToPhoneNumber",Parameters:{PhoneNumber:e.config.phoneNumber},Transitions:r};case"invoke-lambda":return{Identifier:e.id,Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:e.config.functionArn,InvocationTimeLimitSeconds:e.config.timeout},Transitions:r};case"set-attribute":return{Identifier:e.id,Type:"UpdateContactAttributes",Parameters:{Attributes:{[e.config.key]:e.config.value}},Transitions:r};case"check-hours":return{Identifier:e.id,Type:"CheckHoursOfOperation",Parameters:{HoursOfOperationId:e.config.hoursOfOperationArn},Transitions:{NextAction:n,Conditions:[{NextAction:n,Condition:{Operator:"Equals",Operands:["True"]}}],Errors:[{NextAction:"disconnect"}]}};case"wait":return{Identifier:e.id,Type:"Wait",Parameters:{Seconds:e.config.seconds},Transitions:r};case"disconnect":return{Identifier:e.id,Type:"DisconnectParticipant",Parameters:{},Transitions:{}};default:return null}}connectToLast(e){if(this.nodes.length>1){let t=this.nodes[this.nodes.length-2];this.connections.push({id:this.generateId(),sourceNodeId:t.id,targetNodeId:e,sourcePort:"default"})}}getNextNodeId(e){return this.connections.find((n)=>n.sourceNodeId===e)?.targetNodeId||null}generateId(){return`node-${Date.now()}-${Math.random().toString(36).substr(2,9)}`}static Templates={basicSupport:()=>Ke.create("Basic Support").start().playPrompt("Welcome to customer support.").menu("Press 1 for sales, 2 for support, or 3 to leave a message.",{"1":"sales","2":"support","3":"voicemail"}),afterHours:(e)=>Ke.create("After Hours").start().playPrompt(e).recordVoicemail({greeting:"Please leave your name, number, and a brief message.",maxDuration:120}).playPrompt("Thank you for your message. Goodbye.").disconnect(),callbackRequest:(e)=>Ke.create("Callback Request").start().playPrompt("All agents are currently busy.").getInput("Press 1 to request a callback, or 2 to wait.",{maxDigits:1}).invokeLambda(e).playPrompt("We will call you back shortly. Goodbye.").disconnect()}}class On{static MetricsAggregatorCode=`
5663
5663
  const { DynamoDBClient, PutItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
5664
5664
 
5665
5665
  const dynamodb = new DynamoDBClient({});
@@ -5858,7 +5858,7 @@ catch (error) {
5858
5858
  };
5859
5859
  }
5860
5860
  };
5861
- `;static createMetricsTable(e){return{[`${e.slug}CallMetricsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createMetricsAggregatorLambda(e){return{[`${e.slug}CallMetricsAggregatorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-call-metrics-aggregator`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:On.MetricsAggregatorCode},Environment:{Variables:{CALL_LOG_TABLE:e.callLogTable,METRICS_TABLE:e.metricsTable}}}}}}static createMetricsSchedule(e){return{[`${e.slug}CallMetricsSchedule`]:{Type:"AWS::Events::Rule",Properties:{Name:`${e.slug}-call-metrics-schedule`,Description:"Aggregate call metrics hourly",ScheduleExpression:"rate(1 hour)",State:"ENABLED",Targets:[{Id:"MetricsAggregatorTarget",Arn:e.lambdaArn}]}}}}}class xt{static CallbackRequestCode=`
5861
+ `;static createMetricsTable(e){return{[`${e.slug}CallMetricsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createMetricsAggregatorLambda(e){return{[`${e.slug}CallMetricsAggregatorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-call-metrics-aggregator`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:On.MetricsAggregatorCode},Environment:{Variables:{CALL_LOG_TABLE:e.callLogTable,METRICS_TABLE:e.metricsTable}}}}}}static createMetricsSchedule(e){return{[`${e.slug}CallMetricsSchedule`]:{Type:"AWS::Events::Rule",Properties:{Name:`${e.slug}-call-metrics-schedule`,Description:"Aggregate call metrics hourly",ScheduleExpression:"rate(1 hour)",State:"ENABLED",Targets:[{Id:"MetricsAggregatorTarget",Arn:e.lambdaArn}]}}}}}class kt{static CallbackRequestCode=`
5862
5862
  const { DynamoDBClient, PutItemCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
5863
5863
  const { ConnectClient, StartOutboundVoiceContactCommand } = require('@aws-sdk/client-connect');
5864
5864
  const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
@@ -6148,7 +6148,7 @@ catch (error) {
6148
6148
  return { statusCode: 500, error: error.message };
6149
6149
  }
6150
6150
  };
6151
- `;static createCallbacksTable(e){return{[`${e.slug}CallbacksTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCallbackRequestLambda(e){return{[`${e.slug}CallbackRequestLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-callback-request`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:xt.CallbackRequestCode},Environment:{Variables:{CALLBACKS_TABLE:e.callbacksTable,NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||""}}}}}}static createCallbackProcessorLambda(e){return{[`${e.slug}CallbackProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-callback-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:300,MemorySize:256,Code:{ZipFile:xt.CallbackProcessorCode},Environment:{Variables:{CALLBACKS_TABLE:e.callbacksTable,CONNECT_INSTANCE_ID:e.connectInstanceId,CONTACT_FLOW_ID:e.contactFlowId,SOURCE_PHONE_NUMBER:e.sourcePhoneNumber,QUEUE_ID:e.queueId||""}}}}}}}class $n{static CampaignManagerCode=`
6151
+ `;static createCallbacksTable(e){return{[`${e.slug}CallbacksTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCallbackRequestLambda(e){return{[`${e.slug}CallbackRequestLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-callback-request`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:kt.CallbackRequestCode},Environment:{Variables:{CALLBACKS_TABLE:e.callbacksTable,NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||""}}}}}}static createCallbackProcessorLambda(e){return{[`${e.slug}CallbackProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-callback-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:300,MemorySize:256,Code:{ZipFile:kt.CallbackProcessorCode},Environment:{Variables:{CALLBACKS_TABLE:e.callbacksTable,CONNECT_INSTANCE_ID:e.connectInstanceId,CONTACT_FLOW_ID:e.contactFlowId,SOURCE_PHONE_NUMBER:e.sourcePhoneNumber,QUEUE_ID:e.queueId||""}}}}}}}class $n{static CampaignManagerCode=`
6152
6152
  const { DynamoDBClient, PutItemCommand, GetItemCommand, UpdateItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
6153
6153
 
6154
6154
  const dynamodb = new DynamoDBClient({});
@@ -7054,7 +7054,7 @@ function generateShortId() {
7054
7054
  }
7055
7055
  return id;
7056
7056
  }
7057
- `;static createLinksTable(e){return{[`${e.slug}ShortLinksTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createLinkShortenerLambda(e){return{[`${e.slug}LinkShortenerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-link-shortener`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:_n.LinkShortenerCode},Environment:{Variables:{LINKS_TABLE:e.linksTable,SHORT_DOMAIN:e.shortDomain||""}}}}}}static shortenUrlsInMessage(e,t,n){let r=/(https?:\/\/[^\s]+)/g,i=[],s=0;return{message:e.replace(r,(o)=>{let c=`${n}-${s++}`,l=`https://${t}/l/${c}`;return i.push({original:o,short:l,id:c}),l}),links:i}}}class Te{static AbTestManagerCode=`
7057
+ `;static createLinksTable(e){return{[`${e.slug}ShortLinksTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createLinkShortenerLambda(e){return{[`${e.slug}LinkShortenerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-link-shortener`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:_n.LinkShortenerCode},Environment:{Variables:{LINKS_TABLE:e.linksTable,SHORT_DOMAIN:e.shortDomain||""}}}}}}static shortenUrlsInMessage(e,t,n){let r=/(https?:\/\/[^\s]+)/g,i=[],s=0;return{message:e.replace(r,(o)=>{let c=`${n}-${s++}`,l=`https://${t}/l/${c}`;return i.push({original:o,short:l,id:c}),l}),links:i}}}class Pe{static AbTestManagerCode=`
7058
7058
  const { DynamoDBClient, PutItemCommand, GetItemCommand, UpdateItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
7059
7059
 
7060
7060
  const dynamodb = new DynamoDBClient({});
@@ -7248,7 +7248,7 @@ function unmarshallTest(item) {
7248
7248
 
7249
7249
  return test;
7250
7250
  }
7251
- `;static createAbTestsTable(e){return{[`${e.slug}AbTestsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createAbTestManagerLambda(e){return{[`${e.slug}AbTestManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-ab-test-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Te.AbTestManagerCode},Environment:{Variables:{AB_TESTS_TABLE:e.abTestsTable}}}}}}static selectVariant(e,t){let r=Te.hashString(t+e.id)%100,i=0;for(let s=0;s<e.variants.length;s++)if(i+=e.trafficSplit[s],r<i)return e.variants[s];return e.variants[e.variants.length-1]}static determineWinner(e){if(e.variants.length===0)return null;let t=e.winningCriteria,n=e.variants[0],r=Te.getMetricValue(n,t);for(let i of e.variants.slice(1)){let s=Te.getMetricValue(i,t);if(s>r)r=s,n=i}return n}static calculateSignificance(e,t,n){let r=e.stats.sent,i=t.stats.sent;if(r<30||i<30)return 0;let s=Te.getMetricValue(e,n)/100,a=Te.getMetricValue(t,n)/100,o=(s*r+a*i)/(r+i),c=Math.sqrt(o*(1-o)*(1/r+1/i));if(c===0)return 0;let l=Math.abs(s-a)/c;if(l>=2.576)return 99;if(l>=1.96)return 95;if(l>=1.645)return 90;if(l>=1.28)return 80;return Math.round(l*30)}static getMetricValue(e,t){switch(t){case"delivery_rate":return e.stats.deliveryRate;case"click_rate":return e.stats.clickRate;case"reply_rate":return e.stats.replyRate;case"conversion_rate":return e.stats.conversionRate;default:return e.stats.deliveryRate}}static hashString(e){let t=0;for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);t=(t<<5)-t+r,t=t&t}return Math.abs(t)}}class zi{queues=new Map;messageGroups=new Map;deduplicationConfigs=new Map;messages=new Map;queueCounter=0;groupCounter=0;deduplicationCounter=0;messageCounter=0;sequenceCounter=0;createFIFOQueue(e){let t=`fifo-queue-${Date.now()}-${this.queueCounter++}`,n=e.name.endsWith(".fifo")?e.name:`${e.name}.fifo`,{name:r,...i}=e,s={id:t,name:n,queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${n}`,...i};return this.queues.set(t,s),this.createDeduplicationConfig({queueId:t,contentBasedDeduplication:e.contentBasedDeduplication,deduplicationInterval:300}),s}createHighThroughputFIFO(e){return this.createFIFOQueue({name:e.name,contentBasedDeduplication:e.contentBasedDeduplication??!0,deduplicationScope:"messageGroup",fifoThroughputLimit:"perMessageGroupId",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createStandardFIFO(e){return this.createFIFOQueue({name:e.name,contentBasedDeduplication:e.contentBasedDeduplication??!1,deduplicationScope:"queue",fifoThroughputLimit:"perQueue",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createDeduplicationConfig(e){let n={id:`dedup-${Date.now()}-${this.deduplicationCounter++}`,deduplicationHashes:new Map,...e};return this.deduplicationConfigs.set(e.queueId,n),n}sendMessage(e){let t=this.queues.get(e.queueId);if(!t)throw Error(`Queue not found: ${e.queueId}`);let n=this.deduplicationConfigs.get(e.queueId);if(n){let a=e.messageDeduplicationId||(t.contentBasedDeduplication?this.generateHash(e.messageBody):void 0);if(a&&this.isDuplicate(n,a))return null;if(a)n.deduplicationHashes.set(a,new Date)}let r=`msg-${Date.now()}-${this.messageCounter++}`,i=this.generateSequenceNumber(),s={id:r,messageId:r,messageGroupId:e.messageGroupId,messageDeduplicationId:e.messageDeduplicationId,body:e.messageBody,attributes:e.messageAttributes||{},sentTimestamp:new Date,sequenceNumber:i};return this.messages.set(r,s),this.updateMessageGroup(e.queueId,e.messageGroupId),s}isDuplicate(e,t){let n=e.deduplicationHashes.get(t);if(!n)return!1;if((Date.now()-n.getTime())/1000>e.deduplicationInterval)return e.deduplicationHashes.delete(t),!1;return!0}generateHash(e){let t=0;for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);t=(t<<5)-t+r,t=t&t}return Math.abs(t).toString(36)}generateSequenceNumber(){return`${Date.now()}${this.sequenceCounter++}`.padStart(20,"0")}updateMessageGroup(e,t){let n=`${e}-${t}`,r=this.messageGroups.get(n);if(!r)r={id:`group-${Date.now()}-${this.groupCounter++}`,messageGroupId:t,queueId:e,messagesInFlight:0},this.messageGroups.set(n,r);r.messagesInFlight++,r.lastMessageTimestamp=new Date}getMessageGroups(e){return Array.from(this.messageGroups.values()).filter((t)=>t.queueId===e)}getQueue(e){return this.queues.get(e)}listQueues(){return Array.from(this.queues.values())}getMessages(e,t){let n=Array.from(this.messages.values());if(t)n=n.filter((r)=>r.messageGroupId===t);return n.sort((r,i)=>r.sequenceNumber.localeCompare(i.sequenceNumber))}generateFIFOQueueCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:e.name,FifoQueue:!0,ContentBasedDeduplication:e.contentBasedDeduplication,DeduplicationScope:e.deduplicationScope,FifoThroughputLimit:e.fifoThroughputLimit,MessageRetentionPeriod:e.messageRetentionPeriod,VisibilityTimeout:e.visibilityTimeout,ReceiveMessageWaitTimeSeconds:e.receiveMessageWaitTime,...e.deadLetterTargetArn&&{RedrivePolicy:{deadLetterTargetArn:e.deadLetterTargetArn,maxReceiveCount:e.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 aA=new zi;class Qi{monitors=new Map;metrics=new Map;alerts=new Map;reprocessJobs=new Map;monitorCounter=0;metricsCounter=0;alertCounter=0;jobCounter=0;createDLQMonitor(e){let t=`dlq-monitor-${Date.now()}-${this.monitorCounter++}`,n={id:t,...e};return this.monitors.set(t,n),n}createAutomatedMonitor(e){return this.createDLQMonitor({name:e.name,queueUrl:e.queueUrl,sourceQueues:e.sourceQueues,maxReceiveCount:3,alarmThreshold:10,autoReprocess:!0,reprocessStrategy:"scheduled",notificationTopicArn:e.notificationTopicArn})}collectMetrics(e){let n={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:e,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)},r=this.metrics.get(e)||[];return r.push(n),this.metrics.set(e,r),this.checkForAlerts(e,n),n}checkForAlerts(e,t){let n=Array.from(this.monitors.values()).find((i)=>i.queueUrl===e);if(!n)return;if(t.approximateNumberOfMessages>=n.alarmThreshold)this.createAlert({monitorId:n.id,alertType:"threshold_exceeded",severity:"high",message:`DLQ ${n.name} has ${t.approximateNumberOfMessages} messages (threshold: ${n.alarmThreshold})`});let r=3600;if(t.approximateAgeOfOldestMessage>r)this.createAlert({monitorId:n.id,alertType:"old_message",severity:"medium",message:`DLQ ${n.name} has messages older than ${r} seconds`})}createAlert(e){let t=`alert-${Date.now()}-${this.alertCounter++}`,n={id:t,timestamp:new Date,acknowledged:!1,...e};return this.alerts.set(t,n),n}acknowledgeAlert(e){let t=this.alerts.get(e);if(!t)throw Error(`Alert not found: ${e}`);return t.acknowledged=!0,t}createReprocessJob(e){let t=`reprocess-${Date.now()}-${this.jobCounter++}`,n={id:t,queueUrl:e.queueUrl,messageId:e.messageId,attempts:0,status:"pending"};return this.reprocessJobs.set(t,n),n}async executeReprocessJob(e){let t=this.reprocessJobs.get(e);if(!t)throw Error(`Reprocess job not found: ${e}`);t.status="processing",t.startedAt=new Date,t.attempts++,await new Promise((r)=>setTimeout(r,100));let n=Math.random()>0.3;if(t.status=n?"success":"failed",t.completedAt=new Date,!n)t.error="Reprocessing failed - original error still present";return t}async batchReprocess(e){let t=[];for(let n=0;n<e.maxMessages;n++){let r=this.createReprocessJob({queueUrl:e.queueUrl,messageId:`msg-${n}`});await this.executeReprocessJob(r.id),t.push(r)}return t}getDLQStatistics(e,t=24){let n=new Date(Date.now()-t*60*60*1000),r=(this.metrics.get(e)||[]).filter((u)=>u.timestamp>=n);if(r.length===0)return{totalMessages:0,avgAge:0,messagesReceived:0,messagesDeleted:0,messagesReprocessed:0,successRate:0};let i=r[r.length-1],s=r.reduce((u,m)=>u+m.messagesReceived,0),a=r.reduce((u,m)=>u+m.messagesDeleted,0),o=r.reduce((u,m)=>u+m.messagesReprocessed,0),c=r.reduce((u,m)=>u+m.approximateAgeOfOldestMessage,0)/r.length,l=o>0?a/o*100:0;return{totalMessages:i.approximateNumberOfMessages,avgAge:c,messagesReceived:s,messagesDeleted:a,messagesReprocessed:o,successRate:l}}getMonitor(e){return this.monitors.get(e)}listMonitors(){return Array.from(this.monitors.values())}getAlerts(e,t){let n=Array.from(this.alerts.values());if(e)n=n.filter((r)=>r.monitorId===e);if(t!==void 0)n=n.filter((r)=>r.acknowledged===t);return n.sort((r,i)=>i.timestamp.getTime()-r.timestamp.getTime())}getReprocessJobs(e){let t=Array.from(this.reprocessJobs.values());if(e)t=t.filter((n)=>n.queueUrl===e);return t}generateDLQAlarmCF(e){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e.name}-messages-alarm`,AlarmDescription:`Alert when DLQ ${e.name} exceeds threshold`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:1,Threshold:e.alarmThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:e.queueUrl.split("/").pop()}],...e.notificationTopicArn&&{AlarmActions:[e.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 cA=new Qi;class Ji{configs=new Map;jobs=new Map;metrics=new Map;configCounter=0;jobCounter=0;metricsCounter=0;createBatchConfig(e){let t=`batch-config-${Date.now()}-${this.configCounter++}`,n={id:t,...e};return this.configs.set(t,n),n}createHighThroughputConfig(e){return this.createBatchConfig({queueUrl:e.queueUrl,batchSize:10,maxWaitTime:100,parallelProcessors:10,retryAttempts:3,visibilityTimeout:30})}createLowLatencyConfig(e){return this.createBatchConfig({queueUrl:e.queueUrl,batchSize:1,maxWaitTime:0,parallelProcessors:5,retryAttempts:2,visibilityTimeout:10})}createBatchJob(e){let t=`batch-job-${Date.now()}-${this.jobCounter++}`;if(!this.configs.get(e.configId))throw Error(`Batch config not found: ${e.configId}`);let r=[];for(let s=0;s<e.messageCount;s++)r.push({id:`msg-${t}-${s}`,messageId:`${t}-${s}`,body:`Message ${s}`,receiptHandle:`receipt-${t}-${s}`,attributes:{},status:"pending"});let i={id:t,configId:e.configId,messages:r,status:"pending",processedCount:0,failedCount:0};return this.jobs.set(t,i),i}async processBatchJob(e){let t=this.jobs.get(e);if(!t)throw Error(`Batch job not found: ${e}`);let n=this.configs.get(t.configId);if(!n)throw Error(`Batch config not found: ${t.configId}`);t.status="processing",t.startedAt=new Date;let r=this.chunkArray(t.messages,n.batchSize);for(let i of r)await this.processBatch(i,n);return t.processedCount=t.messages.filter((i)=>i.status==="success").length,t.failedCount=t.messages.filter((i)=>i.status==="failed").length,t.status=t.failedCount===0?"completed":"failed",t.completedAt=new Date,this.collectProcessorMetrics(n.id,t),t}async processBatch(e,t){let n=e.map((r)=>this.processMessage(r,t));await Promise.all(n)}async processMessage(e,t){e.status="processing";let n=Date.now();await new Promise((s)=>setTimeout(s,Math.random()*100));let r=Date.now()-n;if(e.processingTime=r,Math.random()>0.1)e.status="success";else e.status="failed",e.error="Processing error"}chunkArray(e,t){let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}collectProcessorMetrics(e,t){let n=`metrics-${Date.now()}-${this.metricsCounter++}`,i=t.messages.filter((m)=>m.status==="success").map((m)=>m.processingTime||0).filter((m)=>m>0),s=i.length>0?i.reduce((m,p)=>m+p,0)/i.length:0,a=t.completedAt&&t.startedAt?(t.completedAt.getTime()-t.startedAt.getTime())/1000:1,o=t.processedCount/a,c=t.messages.length>0?t.failedCount/t.messages.length*100:0,l={id:n,configId:e,timestamp:new Date,messagesProcessed:t.processedCount,averageProcessingTime:s,throughput:o,errorRate:c},u=this.metrics.get(e)||[];u.push(l),this.metrics.set(e,u)}getBatchStatistics(e){let t=this.metrics.get(e)||[];if(t.length===0)return{totalJobsProcessed:0,totalMessagesProcessed:0,averageThroughput:0,averageErrorRate:0,averageProcessingTime:0};let n=t.reduce((a,o)=>a+o.messagesProcessed,0),r=t.reduce((a,o)=>a+o.throughput,0)/t.length,i=t.reduce((a,o)=>a+o.errorRate,0)/t.length,s=t.reduce((a,o)=>a+o.averageProcessingTime,0)/t.length;return{totalJobsProcessed:t.length,totalMessagesProcessed:n,averageThroughput:r,averageErrorRate:i,averageProcessingTime:s}}optimizeBatchConfig(e){let t=this.configs.get(e);if(!t)throw Error(`Batch config not found: ${e}`);let n=this.getBatchStatistics(e);if(n.averageErrorRate<5&&t.batchSize<10)t.batchSize=Math.min(10,t.batchSize+1);if(n.averageErrorRate>20&&t.batchSize>1)t.batchSize=Math.max(1,t.batchSize-1);if(n.averageThroughput<5&&t.parallelProcessors<20)t.parallelProcessors++;return t}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getJob(e){return this.jobs.get(e)}listJobs(e){let t=Array.from(this.jobs.values());if(e)t=t.filter((n)=>n.configId===e);return t}generateBatchProcessorCF(e){return{Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:`arn:aws:sqs:us-east-1:123456789012:${e.queueUrl.split("/").pop()}`,FunctionName:"batch-processor-function",BatchSize:e.batchSize,MaximumBatchingWindowInSeconds:e.maxWaitTime/1000,FunctionResponseTypes:["ReportBatchItemFailures"]}}}clear(){this.configs.clear(),this.jobs.clear(),this.metrics.clear(),this.configCounter=0,this.jobCounter=0,this.metricsCounter=0}}var uA=new Ji;class Yi{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(e){let t=`queue-${Date.now()}-${this.queueCounter++}`,n={id:t,purgeInProgress:!1,...e};return this.queues.set(t,n),n}createStandardQueue(e){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${e.queueName}`,queueName:e.queueName,messageRetentionPeriod:(e.messageRetentionDays||4)*24*60*60,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:0})}createLongPollingQueue(e){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${e.queueName}`,queueName:e.queueName,messageRetentionPeriod:345600,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:e.waitTimeSeconds||20})}createRetentionPolicy(e){let t=`retention-${Date.now()}-${this.retentionCounter++}`,n={id:t,...e};this.retentionPolicies.set(t,n);let r=this.queues.get(e.queueId);if(r)r.messageRetentionPeriod=e.retentionPeriod;return n}createShortRetentionPolicy(e){return this.createRetentionPolicy({queueId:e.queueId,retentionPeriod:e.retentionHours*60*60,autoCleanup:!0,archiveExpiredMessages:!1})}createArchivalRetentionPolicy(e){return this.createRetentionPolicy({queueId:e.queueId,retentionPeriod:e.retentionDays*24*60*60,autoCleanup:!0,cleanupSchedule:"cron(0 0 * * ? *)",archiveExpiredMessages:!0,archiveS3Bucket:e.s3Bucket})}createDelayQueue(e){let t=`delay-${Date.now()}-${this.delayCounter++}`,n={id:t,...e};this.delayQueues.set(t,n);let r=Array.from(this.queues.values()).find((i)=>i.queueUrl===e.queueUrl);if(r)r.delaySeconds=e.defaultDelay;return n}createScheduledDelayQueue(e){return this.createDelayQueue({queueUrl:e.queueUrl,defaultDelay:e.delayMinutes*60,perMessageDelay:!1,maxDelay:900})}async purgeQueue(e){let t=this.queues.get(e);if(!t)throw Error(`Queue not found: ${e}`);if(t.purgeInProgress)throw Error("Purge already in progress for this queue");let n=`purge-${Date.now()}-${this.purgeCounter++}`,r={id:n,queueUrl:t.queueUrl,status:"in_progress",startedAt:new Date};return this.purgeOperations.set(n,r),t.purgeInProgress=!0,setTimeout(()=>{r.status="completed",r.completedAt=new Date,r.messagesPurged=Math.floor(Math.random()*1000),t.purgeInProgress=!1},100),r}collectQueueMetrics(e){let n={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:e,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)},r=this.metrics.get(e)||[];return r.push(n),this.metrics.set(e,r),n}getQueueHealth(e){let t=this.metrics.get(e)||[];if(t.length===0)return{status:"healthy",issues:[],recommendations:[]};let n=t[t.length-1],r=[],i=[],s="healthy";if(n.approximateNumberOfMessages>1e4)s="critical",r.push("Large message backlog detected"),i.push("Increase consumer capacity");else if(n.approximateNumberOfMessages>1000)s="warning",r.push("Growing message backlog"),i.push("Monitor consumer performance");if(n.oldestMessageAge&&n.oldestMessageAge>3600){if(s!=="critical")s="warning";r.push("Old messages in queue"),i.push("Review message processing")}if(n.approximateNumberOfMessagesDelayed>100){if(s!=="critical")s="warning";r.push("High number of delayed messages")}return{status:s,issues:r,recommendations:i}}getQueue(e){return this.queues.get(e)}listQueues(){return Array.from(this.queues.values())}getRetentionPolicy(e){return this.retentionPolicies.get(e)}listRetentionPolicies(){return Array.from(this.retentionPolicies.values())}getPurgeOperations(e){let t=Array.from(this.purgeOperations.values());if(e)t=t.filter((n)=>n.queueUrl===e);return t}generateQueueCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:e.queueName,MessageRetentionPeriod:e.messageRetentionPeriod,DelaySeconds:e.delaySeconds,MaximumMessageSize:e.maximumMessageSize,ReceiveMessageWaitTimeSeconds:e.receiveMessageWaitTime}}}generateCleanupRuleCF(e){return{Type:"AWS::Events::Rule",Properties:{Name:`${e.id}-cleanup`,Description:"Automated queue cleanup",ScheduleExpression:e.cleanupSchedule||"cron(0 0 * * ? *)",State:"ENABLED",Targets:[{Arn:"arn:aws:lambda:us-east-1:123456789012:function:queue-cleanup",Id:e.id,Input:JSON.stringify({queueId:e.queueId,archiveBucket:e.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 mA=new Yi;import{deflateRawSync as jc}from"node:zlib";var Kc=(()=>{let e=[];for(let t=0;t<256;t++){let n=t;for(let r=0;r<8;r++)n=n&1?3988292384^n>>>1:n>>>1;e[t]=n>>>0}return e})();function qc(e){let t=4294967295;for(let n=0;n<e.length;n++)t=Kc[(t^e[n])&255]^t>>>8;return(t^4294967295)>>>0}function zc(e){if(typeof e==="string")return Buffer.from(e,"utf-8");if(Buffer.isBuffer(e))return e;return Buffer.from(e)}function Qc(e){let t=Math.max(1980,e.getFullYear()),n=(e.getHours()<<11|e.getMinutes()<<5|e.getSeconds()>>1)&65535,r=(t-1980<<9|e.getMonth()+1<<5|e.getDate())&65535;return{time:n,date:r}}function he(e){let t=[],n=[],r=0;for(let a of e){let o=zc(a.data),c=jc(o),l=qc(o),u=Buffer.from(a.name.replace(/\\/g,"/"),"utf-8"),{time:m,date:p}=Qc(a.date??new Date(0)),g=a.mode??420,y=Buffer.alloc(30+u.length);y.writeUInt32LE(67324752,0),y.writeUInt16LE(20,4),y.writeUInt16LE(0,6),y.writeUInt16LE(8,8),y.writeUInt16LE(m,10),y.writeUInt16LE(p,12),y.writeUInt32LE(l,14),y.writeUInt32LE(c.length,18),y.writeUInt32LE(o.length,22),y.writeUInt16LE(u.length,26),y.writeUInt16LE(0,28),u.copy(y,30);let h=Buffer.alloc(46+u.length);h.writeUInt32LE(33639248,0),h.writeUInt16LE(798,4),h.writeUInt16LE(20,6),h.writeUInt16LE(0,8),h.writeUInt16LE(8,10),h.writeUInt16LE(m,12),h.writeUInt16LE(p,14),h.writeUInt32LE(l,16),h.writeUInt32LE(c.length,20),h.writeUInt32LE(o.length,24),h.writeUInt16LE(u.length,28),h.writeUInt16LE(0,30),h.writeUInt16LE(0,32),h.writeUInt16LE(0,34),h.writeUInt16LE(0,36),h.writeUInt32LE((g&65535)<<16,38),h.writeUInt32LE(r,42),u.copy(h,46),t.push(y,c),n.push(h),r+=y.length+c.length}let i=Buffer.concat(n),s=Buffer.alloc(22);return s.writeUInt32LE(101010256,0),s.writeUInt16LE(0,4),s.writeUInt16LE(0,6),s.writeUInt16LE(e.length,8),s.writeUInt16LE(e.length,10),s.writeUInt32LE(i.length,12),s.writeUInt32LE(r,16),s.writeUInt16LE(0,20),Buffer.concat([...t,i,s])}function Zi(e){let t=e.adapterImport??"./adapter",n=e.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
7251
+ `;static createAbTestsTable(e){return{[`${e.slug}AbTestsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createAbTestManagerLambda(e){return{[`${e.slug}AbTestManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-ab-test-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Pe.AbTestManagerCode},Environment:{Variables:{AB_TESTS_TABLE:e.abTestsTable}}}}}}static selectVariant(e,t){let r=Pe.hashString(t+e.id)%100,i=0;for(let s=0;s<e.variants.length;s++)if(i+=e.trafficSplit[s],r<i)return e.variants[s];return e.variants[e.variants.length-1]}static determineWinner(e){if(e.variants.length===0)return null;let t=e.winningCriteria,n=e.variants[0],r=Pe.getMetricValue(n,t);for(let i of e.variants.slice(1)){let s=Pe.getMetricValue(i,t);if(s>r)r=s,n=i}return n}static calculateSignificance(e,t,n){let r=e.stats.sent,i=t.stats.sent;if(r<30||i<30)return 0;let s=Pe.getMetricValue(e,n)/100,a=Pe.getMetricValue(t,n)/100,o=(s*r+a*i)/(r+i),c=Math.sqrt(o*(1-o)*(1/r+1/i));if(c===0)return 0;let l=Math.abs(s-a)/c;if(l>=2.576)return 99;if(l>=1.96)return 95;if(l>=1.645)return 90;if(l>=1.28)return 80;return Math.round(l*30)}static getMetricValue(e,t){switch(t){case"delivery_rate":return e.stats.deliveryRate;case"click_rate":return e.stats.clickRate;case"reply_rate":return e.stats.replyRate;case"conversion_rate":return e.stats.conversionRate;default:return e.stats.deliveryRate}}static hashString(e){let t=0;for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);t=(t<<5)-t+r,t=t&t}return Math.abs(t)}}class zi{queues=new Map;messageGroups=new Map;deduplicationConfigs=new Map;messages=new Map;queueCounter=0;groupCounter=0;deduplicationCounter=0;messageCounter=0;sequenceCounter=0;createFIFOQueue(e){let t=`fifo-queue-${Date.now()}-${this.queueCounter++}`,n=e.name.endsWith(".fifo")?e.name:`${e.name}.fifo`,{name:r,...i}=e,s={id:t,name:n,queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${n}`,...i};return this.queues.set(t,s),this.createDeduplicationConfig({queueId:t,contentBasedDeduplication:e.contentBasedDeduplication,deduplicationInterval:300}),s}createHighThroughputFIFO(e){return this.createFIFOQueue({name:e.name,contentBasedDeduplication:e.contentBasedDeduplication??!0,deduplicationScope:"messageGroup",fifoThroughputLimit:"perMessageGroupId",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createStandardFIFO(e){return this.createFIFOQueue({name:e.name,contentBasedDeduplication:e.contentBasedDeduplication??!1,deduplicationScope:"queue",fifoThroughputLimit:"perQueue",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createDeduplicationConfig(e){let n={id:`dedup-${Date.now()}-${this.deduplicationCounter++}`,deduplicationHashes:new Map,...e};return this.deduplicationConfigs.set(e.queueId,n),n}sendMessage(e){let t=this.queues.get(e.queueId);if(!t)throw Error(`Queue not found: ${e.queueId}`);let n=this.deduplicationConfigs.get(e.queueId);if(n){let a=e.messageDeduplicationId||(t.contentBasedDeduplication?this.generateHash(e.messageBody):void 0);if(a&&this.isDuplicate(n,a))return null;if(a)n.deduplicationHashes.set(a,new Date)}let r=`msg-${Date.now()}-${this.messageCounter++}`,i=this.generateSequenceNumber(),s={id:r,messageId:r,messageGroupId:e.messageGroupId,messageDeduplicationId:e.messageDeduplicationId,body:e.messageBody,attributes:e.messageAttributes||{},sentTimestamp:new Date,sequenceNumber:i};return this.messages.set(r,s),this.updateMessageGroup(e.queueId,e.messageGroupId),s}isDuplicate(e,t){let n=e.deduplicationHashes.get(t);if(!n)return!1;if((Date.now()-n.getTime())/1000>e.deduplicationInterval)return e.deduplicationHashes.delete(t),!1;return!0}generateHash(e){let t=0;for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);t=(t<<5)-t+r,t=t&t}return Math.abs(t).toString(36)}generateSequenceNumber(){return`${Date.now()}${this.sequenceCounter++}`.padStart(20,"0")}updateMessageGroup(e,t){let n=`${e}-${t}`,r=this.messageGroups.get(n);if(!r)r={id:`group-${Date.now()}-${this.groupCounter++}`,messageGroupId:t,queueId:e,messagesInFlight:0},this.messageGroups.set(n,r);r.messagesInFlight++,r.lastMessageTimestamp=new Date}getMessageGroups(e){return Array.from(this.messageGroups.values()).filter((t)=>t.queueId===e)}getQueue(e){return this.queues.get(e)}listQueues(){return Array.from(this.queues.values())}getMessages(e,t){let n=Array.from(this.messages.values());if(t)n=n.filter((r)=>r.messageGroupId===t);return n.sort((r,i)=>r.sequenceNumber.localeCompare(i.sequenceNumber))}generateFIFOQueueCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:e.name,FifoQueue:!0,ContentBasedDeduplication:e.contentBasedDeduplication,DeduplicationScope:e.deduplicationScope,FifoThroughputLimit:e.fifoThroughputLimit,MessageRetentionPeriod:e.messageRetentionPeriod,VisibilityTimeout:e.visibilityTimeout,ReceiveMessageWaitTimeSeconds:e.receiveMessageWaitTime,...e.deadLetterTargetArn&&{RedrivePolicy:{deadLetterTargetArn:e.deadLetterTargetArn,maxReceiveCount:e.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 aA=new zi;class Qi{monitors=new Map;metrics=new Map;alerts=new Map;reprocessJobs=new Map;monitorCounter=0;metricsCounter=0;alertCounter=0;jobCounter=0;createDLQMonitor(e){let t=`dlq-monitor-${Date.now()}-${this.monitorCounter++}`,n={id:t,...e};return this.monitors.set(t,n),n}createAutomatedMonitor(e){return this.createDLQMonitor({name:e.name,queueUrl:e.queueUrl,sourceQueues:e.sourceQueues,maxReceiveCount:3,alarmThreshold:10,autoReprocess:!0,reprocessStrategy:"scheduled",notificationTopicArn:e.notificationTopicArn})}collectMetrics(e){let n={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:e,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)},r=this.metrics.get(e)||[];return r.push(n),this.metrics.set(e,r),this.checkForAlerts(e,n),n}checkForAlerts(e,t){let n=Array.from(this.monitors.values()).find((i)=>i.queueUrl===e);if(!n)return;if(t.approximateNumberOfMessages>=n.alarmThreshold)this.createAlert({monitorId:n.id,alertType:"threshold_exceeded",severity:"high",message:`DLQ ${n.name} has ${t.approximateNumberOfMessages} messages (threshold: ${n.alarmThreshold})`});let r=3600;if(t.approximateAgeOfOldestMessage>r)this.createAlert({monitorId:n.id,alertType:"old_message",severity:"medium",message:`DLQ ${n.name} has messages older than ${r} seconds`})}createAlert(e){let t=`alert-${Date.now()}-${this.alertCounter++}`,n={id:t,timestamp:new Date,acknowledged:!1,...e};return this.alerts.set(t,n),n}acknowledgeAlert(e){let t=this.alerts.get(e);if(!t)throw Error(`Alert not found: ${e}`);return t.acknowledged=!0,t}createReprocessJob(e){let t=`reprocess-${Date.now()}-${this.jobCounter++}`,n={id:t,queueUrl:e.queueUrl,messageId:e.messageId,attempts:0,status:"pending"};return this.reprocessJobs.set(t,n),n}async executeReprocessJob(e){let t=this.reprocessJobs.get(e);if(!t)throw Error(`Reprocess job not found: ${e}`);t.status="processing",t.startedAt=new Date,t.attempts++,await new Promise((r)=>setTimeout(r,100));let n=Math.random()>0.3;if(t.status=n?"success":"failed",t.completedAt=new Date,!n)t.error="Reprocessing failed - original error still present";return t}async batchReprocess(e){let t=[];for(let n=0;n<e.maxMessages;n++){let r=this.createReprocessJob({queueUrl:e.queueUrl,messageId:`msg-${n}`});await this.executeReprocessJob(r.id),t.push(r)}return t}getDLQStatistics(e,t=24){let n=new Date(Date.now()-t*60*60*1000),r=(this.metrics.get(e)||[]).filter((u)=>u.timestamp>=n);if(r.length===0)return{totalMessages:0,avgAge:0,messagesReceived:0,messagesDeleted:0,messagesReprocessed:0,successRate:0};let i=r[r.length-1],s=r.reduce((u,m)=>u+m.messagesReceived,0),a=r.reduce((u,m)=>u+m.messagesDeleted,0),o=r.reduce((u,m)=>u+m.messagesReprocessed,0),c=r.reduce((u,m)=>u+m.approximateAgeOfOldestMessage,0)/r.length,l=o>0?a/o*100:0;return{totalMessages:i.approximateNumberOfMessages,avgAge:c,messagesReceived:s,messagesDeleted:a,messagesReprocessed:o,successRate:l}}getMonitor(e){return this.monitors.get(e)}listMonitors(){return Array.from(this.monitors.values())}getAlerts(e,t){let n=Array.from(this.alerts.values());if(e)n=n.filter((r)=>r.monitorId===e);if(t!==void 0)n=n.filter((r)=>r.acknowledged===t);return n.sort((r,i)=>i.timestamp.getTime()-r.timestamp.getTime())}getReprocessJobs(e){let t=Array.from(this.reprocessJobs.values());if(e)t=t.filter((n)=>n.queueUrl===e);return t}generateDLQAlarmCF(e){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e.name}-messages-alarm`,AlarmDescription:`Alert when DLQ ${e.name} exceeds threshold`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:1,Threshold:e.alarmThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:e.queueUrl.split("/").pop()}],...e.notificationTopicArn&&{AlarmActions:[e.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 cA=new Qi;class Ji{configs=new Map;jobs=new Map;metrics=new Map;configCounter=0;jobCounter=0;metricsCounter=0;createBatchConfig(e){let t=`batch-config-${Date.now()}-${this.configCounter++}`,n={id:t,...e};return this.configs.set(t,n),n}createHighThroughputConfig(e){return this.createBatchConfig({queueUrl:e.queueUrl,batchSize:10,maxWaitTime:100,parallelProcessors:10,retryAttempts:3,visibilityTimeout:30})}createLowLatencyConfig(e){return this.createBatchConfig({queueUrl:e.queueUrl,batchSize:1,maxWaitTime:0,parallelProcessors:5,retryAttempts:2,visibilityTimeout:10})}createBatchJob(e){let t=`batch-job-${Date.now()}-${this.jobCounter++}`;if(!this.configs.get(e.configId))throw Error(`Batch config not found: ${e.configId}`);let r=[];for(let s=0;s<e.messageCount;s++)r.push({id:`msg-${t}-${s}`,messageId:`${t}-${s}`,body:`Message ${s}`,receiptHandle:`receipt-${t}-${s}`,attributes:{},status:"pending"});let i={id:t,configId:e.configId,messages:r,status:"pending",processedCount:0,failedCount:0};return this.jobs.set(t,i),i}async processBatchJob(e){let t=this.jobs.get(e);if(!t)throw Error(`Batch job not found: ${e}`);let n=this.configs.get(t.configId);if(!n)throw Error(`Batch config not found: ${t.configId}`);t.status="processing",t.startedAt=new Date;let r=this.chunkArray(t.messages,n.batchSize);for(let i of r)await this.processBatch(i,n);return t.processedCount=t.messages.filter((i)=>i.status==="success").length,t.failedCount=t.messages.filter((i)=>i.status==="failed").length,t.status=t.failedCount===0?"completed":"failed",t.completedAt=new Date,this.collectProcessorMetrics(n.id,t),t}async processBatch(e,t){let n=e.map((r)=>this.processMessage(r,t));await Promise.all(n)}async processMessage(e,t){e.status="processing";let n=Date.now();await new Promise((s)=>setTimeout(s,Math.random()*100));let r=Date.now()-n;if(e.processingTime=r,Math.random()>0.1)e.status="success";else e.status="failed",e.error="Processing error"}chunkArray(e,t){let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}collectProcessorMetrics(e,t){let n=`metrics-${Date.now()}-${this.metricsCounter++}`,i=t.messages.filter((m)=>m.status==="success").map((m)=>m.processingTime||0).filter((m)=>m>0),s=i.length>0?i.reduce((m,p)=>m+p,0)/i.length:0,a=t.completedAt&&t.startedAt?(t.completedAt.getTime()-t.startedAt.getTime())/1000:1,o=t.processedCount/a,c=t.messages.length>0?t.failedCount/t.messages.length*100:0,l={id:n,configId:e,timestamp:new Date,messagesProcessed:t.processedCount,averageProcessingTime:s,throughput:o,errorRate:c},u=this.metrics.get(e)||[];u.push(l),this.metrics.set(e,u)}getBatchStatistics(e){let t=this.metrics.get(e)||[];if(t.length===0)return{totalJobsProcessed:0,totalMessagesProcessed:0,averageThroughput:0,averageErrorRate:0,averageProcessingTime:0};let n=t.reduce((a,o)=>a+o.messagesProcessed,0),r=t.reduce((a,o)=>a+o.throughput,0)/t.length,i=t.reduce((a,o)=>a+o.errorRate,0)/t.length,s=t.reduce((a,o)=>a+o.averageProcessingTime,0)/t.length;return{totalJobsProcessed:t.length,totalMessagesProcessed:n,averageThroughput:r,averageErrorRate:i,averageProcessingTime:s}}optimizeBatchConfig(e){let t=this.configs.get(e);if(!t)throw Error(`Batch config not found: ${e}`);let n=this.getBatchStatistics(e);if(n.averageErrorRate<5&&t.batchSize<10)t.batchSize=Math.min(10,t.batchSize+1);if(n.averageErrorRate>20&&t.batchSize>1)t.batchSize=Math.max(1,t.batchSize-1);if(n.averageThroughput<5&&t.parallelProcessors<20)t.parallelProcessors++;return t}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getJob(e){return this.jobs.get(e)}listJobs(e){let t=Array.from(this.jobs.values());if(e)t=t.filter((n)=>n.configId===e);return t}generateBatchProcessorCF(e){return{Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:`arn:aws:sqs:us-east-1:123456789012:${e.queueUrl.split("/").pop()}`,FunctionName:"batch-processor-function",BatchSize:e.batchSize,MaximumBatchingWindowInSeconds:e.maxWaitTime/1000,FunctionResponseTypes:["ReportBatchItemFailures"]}}}clear(){this.configs.clear(),this.jobs.clear(),this.metrics.clear(),this.configCounter=0,this.jobCounter=0,this.metricsCounter=0}}var uA=new Ji;class Yi{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(e){let t=`queue-${Date.now()}-${this.queueCounter++}`,n={id:t,purgeInProgress:!1,...e};return this.queues.set(t,n),n}createStandardQueue(e){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${e.queueName}`,queueName:e.queueName,messageRetentionPeriod:(e.messageRetentionDays||4)*24*60*60,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:0})}createLongPollingQueue(e){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${e.queueName}`,queueName:e.queueName,messageRetentionPeriod:345600,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:e.waitTimeSeconds||20})}createRetentionPolicy(e){let t=`retention-${Date.now()}-${this.retentionCounter++}`,n={id:t,...e};this.retentionPolicies.set(t,n);let r=this.queues.get(e.queueId);if(r)r.messageRetentionPeriod=e.retentionPeriod;return n}createShortRetentionPolicy(e){return this.createRetentionPolicy({queueId:e.queueId,retentionPeriod:e.retentionHours*60*60,autoCleanup:!0,archiveExpiredMessages:!1})}createArchivalRetentionPolicy(e){return this.createRetentionPolicy({queueId:e.queueId,retentionPeriod:e.retentionDays*24*60*60,autoCleanup:!0,cleanupSchedule:"cron(0 0 * * ? *)",archiveExpiredMessages:!0,archiveS3Bucket:e.s3Bucket})}createDelayQueue(e){let t=`delay-${Date.now()}-${this.delayCounter++}`,n={id:t,...e};this.delayQueues.set(t,n);let r=Array.from(this.queues.values()).find((i)=>i.queueUrl===e.queueUrl);if(r)r.delaySeconds=e.defaultDelay;return n}createScheduledDelayQueue(e){return this.createDelayQueue({queueUrl:e.queueUrl,defaultDelay:e.delayMinutes*60,perMessageDelay:!1,maxDelay:900})}async purgeQueue(e){let t=this.queues.get(e);if(!t)throw Error(`Queue not found: ${e}`);if(t.purgeInProgress)throw Error("Purge already in progress for this queue");let n=`purge-${Date.now()}-${this.purgeCounter++}`,r={id:n,queueUrl:t.queueUrl,status:"in_progress",startedAt:new Date};return this.purgeOperations.set(n,r),t.purgeInProgress=!0,setTimeout(()=>{r.status="completed",r.completedAt=new Date,r.messagesPurged=Math.floor(Math.random()*1000),t.purgeInProgress=!1},100),r}collectQueueMetrics(e){let n={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:e,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)},r=this.metrics.get(e)||[];return r.push(n),this.metrics.set(e,r),n}getQueueHealth(e){let t=this.metrics.get(e)||[];if(t.length===0)return{status:"healthy",issues:[],recommendations:[]};let n=t[t.length-1],r=[],i=[],s="healthy";if(n.approximateNumberOfMessages>1e4)s="critical",r.push("Large message backlog detected"),i.push("Increase consumer capacity");else if(n.approximateNumberOfMessages>1000)s="warning",r.push("Growing message backlog"),i.push("Monitor consumer performance");if(n.oldestMessageAge&&n.oldestMessageAge>3600){if(s!=="critical")s="warning";r.push("Old messages in queue"),i.push("Review message processing")}if(n.approximateNumberOfMessagesDelayed>100){if(s!=="critical")s="warning";r.push("High number of delayed messages")}return{status:s,issues:r,recommendations:i}}getQueue(e){return this.queues.get(e)}listQueues(){return Array.from(this.queues.values())}getRetentionPolicy(e){return this.retentionPolicies.get(e)}listRetentionPolicies(){return Array.from(this.retentionPolicies.values())}getPurgeOperations(e){let t=Array.from(this.purgeOperations.values());if(e)t=t.filter((n)=>n.queueUrl===e);return t}generateQueueCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:e.queueName,MessageRetentionPeriod:e.messageRetentionPeriod,DelaySeconds:e.delaySeconds,MaximumMessageSize:e.maximumMessageSize,ReceiveMessageWaitTimeSeconds:e.receiveMessageWaitTime}}}generateCleanupRuleCF(e){return{Type:"AWS::Events::Rule",Properties:{Name:`${e.id}-cleanup`,Description:"Automated queue cleanup",ScheduleExpression:e.cleanupSchedule||"cron(0 0 * * ? *)",State:"ENABLED",Targets:[{Arn:"arn:aws:lambda:us-east-1:123456789012:function:queue-cleanup",Id:e.id,Input:JSON.stringify({queueId:e.queueId,archiveBucket:e.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 mA=new Yi;import{deflateRawSync as jc}from"node:zlib";var Kc=(()=>{let e=[];for(let t=0;t<256;t++){let n=t;for(let r=0;r<8;r++)n=n&1?3988292384^n>>>1:n>>>1;e[t]=n>>>0}return e})();function qc(e){let t=4294967295;for(let n=0;n<e.length;n++)t=Kc[(t^e[n])&255]^t>>>8;return(t^4294967295)>>>0}function zc(e){if(typeof e==="string")return Buffer.from(e,"utf-8");if(Buffer.isBuffer(e))return e;return Buffer.from(e)}function Qc(e){let t=Math.max(1980,e.getFullYear()),n=(e.getHours()<<11|e.getMinutes()<<5|e.getSeconds()>>1)&65535,r=(t-1980<<9|e.getMonth()+1<<5|e.getDate())&65535;return{time:n,date:r}}function Se(e){let t=[],n=[],r=0;for(let a of e){let o=zc(a.data),c=jc(o),l=qc(o),u=Buffer.from(a.name.replace(/\\/g,"/"),"utf-8"),{time:m,date:p}=Qc(a.date??new Date(0)),g=a.mode??420,y=Buffer.alloc(30+u.length);y.writeUInt32LE(67324752,0),y.writeUInt16LE(20,4),y.writeUInt16LE(0,6),y.writeUInt16LE(8,8),y.writeUInt16LE(m,10),y.writeUInt16LE(p,12),y.writeUInt32LE(l,14),y.writeUInt32LE(c.length,18),y.writeUInt32LE(o.length,22),y.writeUInt16LE(u.length,26),y.writeUInt16LE(0,28),u.copy(y,30);let h=Buffer.alloc(46+u.length);h.writeUInt32LE(33639248,0),h.writeUInt16LE(798,4),h.writeUInt16LE(20,6),h.writeUInt16LE(0,8),h.writeUInt16LE(8,10),h.writeUInt16LE(m,12),h.writeUInt16LE(p,14),h.writeUInt32LE(l,16),h.writeUInt32LE(c.length,20),h.writeUInt32LE(o.length,24),h.writeUInt16LE(u.length,28),h.writeUInt16LE(0,30),h.writeUInt16LE(0,32),h.writeUInt16LE(0,34),h.writeUInt16LE(0,36),h.writeUInt32LE((g&65535)<<16,38),h.writeUInt32LE(r,42),u.copy(h,46),t.push(y,c),n.push(h),r+=y.length+c.length}let i=Buffer.concat(n),s=Buffer.alloc(22);return s.writeUInt32LE(101010256,0),s.writeUInt16LE(0,4),s.writeUInt16LE(0,6),s.writeUInt16LE(e.length,8),s.writeUInt16LE(e.length,10),s.writeUInt32LE(i.length,12),s.writeUInt32LE(r,16),s.writeUInt16LE(0,20),Buffer.concat([...t,i,s])}function Zi(e){let t=e.adapterImport??"./adapter",n=e.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
7252
7252
  import * as __userModule from ${JSON.stringify(n)}
7253
7253
  import { resolveApp, createHandlers } from ${JSON.stringify(t)}
7254
7254
 
@@ -7258,9 +7258,9 @@ const __handlers = createHandlers(__app)
7258
7258
  export const http = __handlers.http
7259
7259
  export const queue = __handlers.queue
7260
7260
  export const cli = __handlers.cli
7261
- `}import{execSync as Jc}from"node:child_process";import{createHash as Yc}from"node:crypto";import{cpSync as Zc,mkdtempSync as Xc,rmSync as el,writeFileSync as tl}from"node:fs";import{tmpdir as nl}from"node:os";import{dirname as rl,isAbsolute as il,join as je,resolve as sl}from"node:path";import{fileURLToPath as al}from"node:url";var ol=["adapter.ts","recursion.ts","auto-recursion.ts"];function cl(){return je(rl(al(import.meta.url)),"runtime")}function ll(e,t,n){for(let r of e??[])n?.(`build: ${r}`),Jc(r,{stdio:"inherit",cwd:t})}function ul(e){return Yc("sha256").update(e).digest("hex")}function NA(e,t,n){return`deployments/${e}/${t}/${n}.zip`}async function xA(e){let t=sl(e.projectRoot??process.cwd()),{app:n}=e;if(!e.skipBuild)ll(n.build,t,e.onStep);let r=n.entry;if(!r)throw Error("serverless app: `entry` is required to package a Node/Bun application");let i=il(r)?r:je(t,r),s=Xc(je(nl(),"tscloud-pkg-"));try{for(let p of ol)Zc(je(cl(),p),je(s,p));let a=je(s,"bootstrap.ts");tl(a,Zi({entryImport:i,adapterImport:"./adapter"})),e.onStep?.("bundling application");let o=await Bun.build({entrypoints:[a],target:n.kind==="bun"?"bun":"node",format:"esm",minify:!1,sourcemap:"none"});if(!o.success){let p=o.logs.map((g)=>String(g)).join(`
7261
+ `}import{execSync as Jc}from"node:child_process";import{createHash as Yc}from"node:crypto";import{cpSync as Zc,mkdtempSync as Xc,rmSync as el,writeFileSync as tl}from"node:fs";import{tmpdir as nl}from"node:os";import{dirname as rl,isAbsolute as il,join as qe,resolve as sl}from"node:path";import{fileURLToPath as al}from"node:url";var ol=["adapter.ts","recursion.ts","auto-recursion.ts"];function cl(){return qe(rl(al(import.meta.url)),"runtime")}function ll(e,t,n){for(let r of e??[])n?.(`build: ${r}`),Jc(r,{stdio:"inherit",cwd:t})}function ul(e){return Yc("sha256").update(e).digest("hex")}function NA(e,t,n){return`deployments/${e}/${t}/${n}.zip`}async function xA(e){let t=sl(e.projectRoot??process.cwd()),{app:n}=e;if(!e.skipBuild)ll(n.build,t,e.onStep);let r=n.entry;if(!r)throw Error("serverless app: `entry` is required to package a Node/Bun application");let i=il(r)?r:qe(t,r),s=Xc(qe(nl(),"tscloud-pkg-"));try{for(let p of ol)Zc(qe(cl(),p),qe(s,p));let a=qe(s,"bootstrap.ts");tl(a,Zi({entryImport:i,adapterImport:"./adapter"})),e.onStep?.("bundling application");let o=await Bun.build({entrypoints:[a],target:n.kind==="bun"?"bun":"node",format:"esm",minify:!1,sourcemap:"none"});if(!o.success){let p=o.logs.map((g)=>String(g)).join(`
7262
7262
  `);throw Error(`serverless app bundle failed:
7263
- ${p}`)}let c=o.outputs[0],l=Buffer.from(await c.arrayBuffer()),u="index",m=he([{name:`${u}.mjs`,data:l}]);return{zip:m,bundle:l,sha256:ul(m),handlerFile:u,handlers:{http:n.handlers?.http??`${u}.http`,queue:n.handlers?.queue??`${u}.queue`,cli:n.handlers?.cli??`${u}.cli`},bundleBytes:l.length}}finally{el(s,{recursive:!0,force:!0})}}var dl=["18","20","22"];function ml(e){if(!e)return"22";let t=String(e).match(/(\d+)/);return t?t[1]:"22"}function Xi(e){let t=e.kind??"node";if(t==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(t==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let n=ml(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&dl.includes(n))return{lambdaRuntime:e.runtime&&e.runtime.startsWith("nodejs")?e.runtime:`nodejs${n}.x`,kind:"node",version:n,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:n,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function es(e,t,n){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${t}-${n}-default`}];return e.queues.map((r)=>{if(typeof r==="string")return{name:`${t}-${n}-${r}`};let[i,s]=Object.entries(r)[0];return{name:`${t}-${n}-${i}`,concurrency:s}})}function BA(e,t,n){return es(e,t,n).map((r)=>r.name)}function FA(e){let{app:t,environment:n,handlers:r}=e,i=e.config.project.slug,s=Xi(t).lambdaRuntime,a=t.architecture??"x86_64",o=e.config.project.region,c={http:`${i}-${n}-http`,queue:`${i}-${n}-queue`,cli:`${i}-${n}-cli`};if(t.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 l=es(t,i,n),u=l.map((N)=>N.name),m=u.length>0,p=t.logRetention??14,g=t.packaging==="image";if(g&&t.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 y=(t.scheduler??"on")!=="off",h=(t.cache?.driver??"dynamodb")==="dynamodb",b=Boolean(t.assets),v=Xn(i,n),T=t.tmpStorage??512,A={},R={},P=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:d.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:d.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${i}-${n}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[d.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${i}/${n}/*`),d.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${i}/${n}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[d.sub(`arn:aws:s3:::${v}`),d.sub(`arn:aws:s3:::${v}/*`),...t.storage?.bucket?[d.sub(`arn:aws:s3:::${t.storage.bucket}`),d.sub(`arn:aws:s3:::${t.storage.bucket}/*`)]:[]]}]}}];if(m)P[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:d.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${i}-${n}-*`)});if(h)P[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:d.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${i}-${n}-cache*`)});let E=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(t.vpc?.subnets?.length)E.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(t.lambdaInsights)E.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");A.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${i}-${n}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:E,Policies:P}};let w=(N)=>({TSCLOUD_LAMBDA_MODE:N,TSCLOUD_ENV:n,...t.octane?{TSCLOUD_OCTANE:"1"}:{},...t.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...h?{TSCLOUD_CACHE_TABLE:`${i}-${n}-cache`}:{},...m?{TSCLOUD_QUEUE:u[0]}:{},...t.env??{}}),I=Boolean(t.efs),D=typeof t.efs==="object"?t.efs:{},k=D.mountPath??"/mnt/local",O=I&&!D.accessPointArn,j=D.accessPointArn??(O?d.getAtt("EfsAccessPoint","Arn"):void 0),K=t.vpc?.subnets??[],re=K.length>0,U=t.cache?.driver==="elasticache"||t.database?.connection==="aurora-serverless"||Boolean(t.rdsProxy)||I;if(U&&!re)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let Pe=re?{VpcConfig:{SubnetIds:K,SecurityGroupIds:[...t.vpc?.securityGroups??[],...U?[d.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},qe=O?K.map((N,M)=>`EfsMountTarget${M}`):[],Bt=I?{FileSystemConfigs:[{Arn:j,LocalMountPath:k}]}:{};if(I)P[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function ue(N,M,F,L,ae,Ft,Qe,we=T){A[`${N}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${M}`,RetentionInDays:p}};let Je=[...e.runtimeLayers??[],...t.lambdaInsights?[t.lambdaInsights.layerArn]:[]],zn=g?{PackageType:"Image",Code:{ImageUri:d.ref("ImageUri")},...t.kind==="php"?{}:{ImageConfig:{Command:[F]}}}:{Runtime:s,Handler:F,Code:{S3Bucket:d.ref("ArtifactBucket"),S3Key:d.ref("ArtifactKey")},...Je.length?{Layers:[...new Set(Je)]}:{}};A[N]={Type:"AWS::Lambda::Function",DependsOn:[`${N}LogGroup`,...qe],Properties:{FunctionName:M,Architectures:[a],MemorySize:ae,Timeout:Ft,Role:d.getAtt("AppRole","Arn"),Environment:{Variables:w(L)},EphemeralStorage:{Size:we},...zn,...Qe!==void 0?{ReservedConcurrentExecutions:Qe}:{},...Pe,...Bt}}}if(ue("HttpFunction",c.http,r.http,"http",t.memory??1024,t.timeout??28,t.concurrency,T),ue("CliFunction",c.cli,r.cli,"cli",t.cliMemory??1024,t.cliTimeout??900,void 0,t.cliTmpStorage??T),m)ue("QueueFunction",c.queue,r.queue,"queue",t.queueMemory??1024,t.queueTimeout??120,void 0,t.queueTmpStorage??T);let se=(t.provisionedConcurrency??0)>0?t.provisionedConcurrency:0,de=["HttpFunction","CliFunction",...m?["QueueFunction"]:[]];if(se)for(let N of de)A[`${N}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:d.ref(N)}},A[`${N}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:d.ref(N),Name:"live",FunctionVersion:d.getAtt(`${N}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:se}}};let Ee=(N)=>se?d.ref(`${N}Alias`):d.getAtt(N,"Arn"),me=(N)=>se?d.ref(`${N}Alias`):d.ref(N);A.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${i}-${n}`,ProtocolType:"HTTP"}},A.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:d.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:Ee("HttpFunction"),PayloadFormatVersion:"2.0"}},A.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:d.ref("HttpApi"),RouteKey:"$default",Target:d.join("/",["integrations",d.ref("HttpIntegration")])}},A.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:d.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},A.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:me("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:d.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},R.HttpApiEndpoint={Description:"HTTP API endpoint",Value:d.getAtt("HttpApi","ApiEndpoint")},R.HttpApiId={Description:"HTTP API id",Value:d.ref("HttpApi")};let Se=(Array.isArray(t.domain)?t.domain:t.domain?[t.domain]:[]).filter(Boolean);if(Se.length){if(!t.certificateArn&&!t.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let N=t.certificateArn;if(!N)A.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:Se[0],...Se.length>1?{SubjectAlternativeNames:Se.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:Se.map((M)=>({DomainName:M,HostedZoneId:t.hostedZoneId}))}},N=d.ref("HttpCertificate");Se.forEach((M,F)=>{let L=`HttpDomain${F}`;if(A[L]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:M,DomainNameConfigurations:[{CertificateArn:N,EndpointType:"REGIONAL"}]}},A[`HttpApiMapping${F}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:d.ref("HttpApi"),DomainName:d.ref(L),Stage:"$default"}},t.hostedZoneId)A[`HttpDomainRecord${F}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t.hostedZoneId,Name:M,Type:"A",AliasTarget:{DNSName:d.getAtt(L,"RegionalDomainName"),HostedZoneId:d.getAtt(L,"RegionalHostedZoneId")}}};R[`CustomDomain${F}`]={Description:`Custom domain ${M}`,Value:M},R[`CustomDomainTarget${F}`]={Description:`Point ${M} (CNAME/alias) at this APIGW regional domain`,Value:d.getAtt(L,"RegionalDomainName")}})}if(m)A.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${i}-${n}-dlq`,MessageRetentionPeriod:1209600}},l.forEach((N,M)=>{let F=`AppQueue${M}`,L=t.queueTimeout??120;A[F]={Type:"AWS::SQS::Queue",Properties:{QueueName:N.name,VisibilityTimeout:Math.min(43200,L*6),RedrivePolicy:{deadLetterTargetArn:d.getAtt("AppQueueDlq","Arn"),maxReceiveCount:t.queueTries??3}}};let ae=N.concurrency??t.queueConcurrency;A[`${F}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:d.getAtt(F,"Arn"),FunctionName:me("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...ae?{ScalingConfig:{MaximumConcurrency:Math.max(2,ae)}}:{}}},R[`QueueUrl${M}`]={Description:`Queue URL: ${N.name}`,Value:d.ref(F)}});if(y)A.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${n}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:Ee("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},A.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:me("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:d.getAtt("SchedulerRule","Arn")}};if(t.warm&&t.warm>0){let M={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},F=(t.warmFunctions??["http"]).filter((L)=>L!=="queue"||m);for(let L of F){let ae=L.charAt(0).toUpperCase()+L.slice(1),Ft=Math.ceil(t.warm/5),Qe=0;for(let we=0;we<Ft;we++){let Je=Math.min(5,t.warm-Qe);A[`Warmer${ae}Rule${we}`]={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${n}-warmer-${L}-${we}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Je},(zn,ks)=>({Id:`warm-${L}-${we}-${ks}`,Arn:d.getAtt(M[L],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Qe+=Je}A[`Warmer${ae}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:d.ref(M[L]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:d.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${i}-${n}-warmer-${L}-*`)}}}}if(h)A.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${i}-${n}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},R.CacheTableName={Description:"DynamoDB cache table",Value:d.ref("CacheTable")};if(b){if(A.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:v,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},A.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${i}-${n}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},A.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:d.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:d.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...t.assetDomain?{Aliases:[t.assetDomain],ViewerCertificate:{AcmCertificateArn:t.assetCertificateArn??d.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},t.assetDomain){if(!t.assetCertificateArn){if(!t.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(o!=="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 ${o}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);A.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:t.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:t.assetDomain,HostedZoneId:t.hostedZoneId}]}}}if(t.hostedZoneId)A.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t.hostedZoneId,Name:t.assetDomain,Type:"A",AliasTarget:{DNSName:d.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};R.AssetDomain={Description:"Custom asset CDN host",Value:t.assetDomain}}A.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:d.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:d.sub(`arn:aws:s3:::${v}/*`),Condition:{StringEquals:{"AWS:SourceArn":d.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},R.AssetsBucketName={Description:"Assets bucket",Value:d.ref("AssetsBucket")},R.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:d.getAtt("AssetsDistribution","DomainName")}}if(t.firewall?.enabled){let N=[],M=0;if(t.firewall.rateLimit)N.push({Name:"rate-limit",Priority:M++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:t.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${n}-rate`}});let F={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let L of t.firewall.rules??[]){let ae=F[L];if(!ae)continue;N.push({Name:`managed-${L}`,Priority:M++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:ae}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${n}-${L}`}})}A.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${i}-${n}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:N,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${n}-waf`}}},R.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:d.getAtt("WebAcl","Arn")}}if(re&&U){if(!t.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.");A.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:t.vpc.id,GroupDescription:`${i}-${n} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(O)A.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${i}-${n}-efs`}]}},K.forEach((N,M)=>{A[`EfsMountTarget${M}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:d.ref("EfsFileSystem"),SubnetId:N,SecurityGroups:[d.getAtt("DataSecurityGroup","GroupId")]}}}),A.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:d.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},R.EfsFileSystemId={Description:"EFS file system id",Value:d.ref("EfsFileSystem")};if(t.cache?.driver==="elasticache")A.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${i}-${n} cache subnets`,SubnetIds:K}},A.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${i}-${n}-cache`,ReplicationGroupDescription:`${i}-${n} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),SecurityGroupIds:[d.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},R.CacheEndpoint={Description:"Redis primary endpoint",Value:d.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(t.database?.connection==="aurora-serverless")A.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${i}-${n} db subnets`,SubnetIds:K}},A.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${i}/${n}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},A.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${i}-${n}-db`,DatabaseName:"app",MasterUsername:d.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:d.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:t.database?.minCapacity??0.5,MaxCapacity:t.database?.maxCapacity??4},DBSubnetGroupName:d.ref("DbSubnetGroup"),VpcSecurityGroupIds:[d.getAtt("DataSecurityGroup","GroupId")]}},A.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:d.ref("DbCluster")}},R.DbEndpoint={Description:"Aurora cluster endpoint",Value:d.getAtt("DbCluster","Endpoint.Address")};if(t.rdsProxy&&t.database?.connection==="aurora-serverless")A.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:d.ref("DbSecret")}]}}]}},A.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof t.rdsProxy==="object"&&t.rdsProxy.name?t.rdsProxy.name:`${i}-${n}-proxy`,EngineFamily:"MYSQL",RoleArn:d.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:d.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:K,VpcSecurityGroupIds:[d.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},A.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:d.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[d.ref("DbCluster")]}},R.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:d.getAtt("DbProxy","Endpoint")};if(R.HttpFunctionName={Description:"HTTP function name",Value:d.ref("HttpFunction")},R.CliFunctionName={Description:"CLI function name",Value:d.ref("CliFunction")},m)R.QueueFunctionName={Description:"Queue function name",Value:d.ref("QueueFunction")};let Le={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${i}-${n})`,Parameters:g?{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:A,Outputs:R},ze={};for(let N of Object.values(A))ze[N.Type]=(ze[N.Type]??0)+1;return{template:Le,functionNames:c,queueNames:u,resourceSummary:ze}}var pl=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function gl(e){let t=`php${e.replace(".","")}`;return pl.map((n)=>`${t}-php-${n}`)}function Wn(e,t){let n=`php${e.replace(".","")}`,r=gl(e).join(" \\\n "),i=`/opt/remi/${n}/root`,s=`/etc/opt/remi/${n}`;return`${t?`FROM almalinux:9 AS ${t}`:"FROM almalinux:9"}
7263
+ ${p}`)}let c=o.outputs[0],l=Buffer.from(await c.arrayBuffer()),u="index",m=Se([{name:`${u}.mjs`,data:l}]);return{zip:m,bundle:l,sha256:ul(m),handlerFile:u,handlers:{http:n.handlers?.http??`${u}.http`,queue:n.handlers?.queue??`${u}.queue`,cli:n.handlers?.cli??`${u}.cli`},bundleBytes:l.length}}finally{el(s,{recursive:!0,force:!0})}}var dl=["18","20","22"];function ml(e){if(!e)return"22";let t=String(e).match(/(\d+)/);return t?t[1]:"22"}function Xi(e){let t=e.kind??"node";if(t==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(t==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let n=ml(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&dl.includes(n))return{lambdaRuntime:e.runtime&&e.runtime.startsWith("nodejs")?e.runtime:`nodejs${n}.x`,kind:"node",version:n,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:n,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function es(e,t,n){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${t}-${n}-default`}];return e.queues.map((r)=>{if(typeof r==="string")return{name:`${t}-${n}-${r}`};let[i,s]=Object.entries(r)[0];return{name:`${t}-${n}-${i}`,concurrency:s}})}function BA(e,t,n){return es(e,t,n).map((r)=>r.name)}function FA(e){let{app:t,environment:n,handlers:r}=e,i=e.config.project.slug,s=Xi(t).lambdaRuntime,a=t.architecture??"x86_64",o=e.config.project.region,c={http:`${i}-${n}-http`,queue:`${i}-${n}-queue`,cli:`${i}-${n}-cli`};if(t.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 l=es(t,i,n),u=l.map((N)=>N.name),m=u.length>0,p=t.logRetention??14,g=t.packaging==="image";if(g&&t.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 y=(t.scheduler??"on")!=="off",h=(t.cache?.driver??"dynamodb")==="dynamodb",b=Boolean(t.assets),C=Xn(i,n),T=t.tmpStorage??512,A={},R={},P=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:d.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:d.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${i}-${n}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[d.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${i}/${n}/*`),d.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${i}/${n}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[d.sub(`arn:aws:s3:::${C}`),d.sub(`arn:aws:s3:::${C}/*`),...t.storage?.bucket?[d.sub(`arn:aws:s3:::${t.storage.bucket}`),d.sub(`arn:aws:s3:::${t.storage.bucket}/*`)]:[]]}]}}];if(m)P[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:d.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${i}-${n}-*`)});if(h)P[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:d.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${i}-${n}-cache*`)});let E=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(t.vpc?.subnets?.length)E.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(t.lambdaInsights)E.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");A.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${i}-${n}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:E,Policies:P}};let w=(N)=>({TSCLOUD_LAMBDA_MODE:N,TSCLOUD_ENV:n,...t.octane?{TSCLOUD_OCTANE:"1"}:{},...t.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...h?{TSCLOUD_CACHE_TABLE:`${i}-${n}-cache`}:{},...m?{TSCLOUD_QUEUE:u[0]}:{},...t.env??{}}),I=Boolean(t.efs),D=typeof t.efs==="object"?t.efs:{},k=D.mountPath??"/mnt/local",O=I&&!D.accessPointArn,ne=D.accessPointArn??(O?d.getAtt("EfsAccessPoint","Arn"):void 0),_=t.vpc?.subnets??[],q=_.length>0,F=t.cache?.driver==="elasticache"||t.database?.connection==="aurora-serverless"||Boolean(t.rdsProxy)||I;if(F&&!q)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let K=q?{VpcConfig:{SubnetIds:_,SecurityGroupIds:[...t.vpc?.securityGroups??[],...F?[d.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},de=O?_.map((N,M)=>`EfsMountTarget${M}`):[],Oe=I?{FileSystemConfigs:[{Arn:ne,LocalMountPath:k}]}:{};if(I)P[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function me(N,M,G,L,oe,Ft,Je,Ie=T){A[`${N}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${M}`,RetentionInDays:p}};let Ye=[...e.runtimeLayers??[],...t.lambdaInsights?[t.lambdaInsights.layerArn]:[]],zn=g?{PackageType:"Image",Code:{ImageUri:d.ref("ImageUri")},...t.kind==="php"?{}:{ImageConfig:{Command:[G]}}}:{Runtime:s,Handler:G,Code:{S3Bucket:d.ref("ArtifactBucket"),S3Key:d.ref("ArtifactKey")},...Ye.length?{Layers:[...new Set(Ye)]}:{}};A[N]={Type:"AWS::Lambda::Function",DependsOn:[`${N}LogGroup`,...de],Properties:{FunctionName:M,Architectures:[a],MemorySize:oe,Timeout:Ft,Role:d.getAtt("AppRole","Arn"),Environment:{Variables:w(L)},EphemeralStorage:{Size:Ie},...zn,...Je!==void 0?{ReservedConcurrentExecutions:Je}:{},...K,...Oe}}}if(me("HttpFunction",c.http,r.http,"http",t.memory??1024,t.timeout??28,t.concurrency,T),me("CliFunction",c.cli,r.cli,"cli",t.cliMemory??1024,t.cliTimeout??900,void 0,t.cliTmpStorage??T),m)me("QueueFunction",c.queue,r.queue,"queue",t.queueMemory??1024,t.queueTimeout??120,void 0,t.queueTmpStorage??T);let ae=(t.provisionedConcurrency??0)>0?t.provisionedConcurrency:0,pe=["HttpFunction","CliFunction",...m?["QueueFunction"]:[]];if(ae)for(let N of pe)A[`${N}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:d.ref(N)}},A[`${N}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:d.ref(N),Name:"live",FunctionVersion:d.getAtt(`${N}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:ae}}};let we=(N)=>ae?d.ref(`${N}Alias`):d.getAtt(N,"Arn"),ge=(N)=>ae?d.ref(`${N}Alias`):d.ref(N);A.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${i}-${n}`,ProtocolType:"HTTP"}},A.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:d.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:we("HttpFunction"),PayloadFormatVersion:"2.0"}},A.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:d.ref("HttpApi"),RouteKey:"$default",Target:d.join("/",["integrations",d.ref("HttpIntegration")])}},A.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:d.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},A.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ge("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:d.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},R.HttpApiEndpoint={Description:"HTTP API endpoint",Value:d.getAtt("HttpApi","ApiEndpoint")},R.HttpApiId={Description:"HTTP API id",Value:d.ref("HttpApi")};let Ce=(Array.isArray(t.domain)?t.domain:t.domain?[t.domain]:[]).filter(Boolean);if(Ce.length){if(!t.certificateArn&&!t.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let N=t.certificateArn;if(!N)A.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:Ce[0],...Ce.length>1?{SubjectAlternativeNames:Ce.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:Ce.map((M)=>({DomainName:M,HostedZoneId:t.hostedZoneId}))}},N=d.ref("HttpCertificate");Ce.forEach((M,G)=>{let L=`HttpDomain${G}`;if(A[L]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:M,DomainNameConfigurations:[{CertificateArn:N,EndpointType:"REGIONAL"}]}},A[`HttpApiMapping${G}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:d.ref("HttpApi"),DomainName:d.ref(L),Stage:"$default"}},t.hostedZoneId)A[`HttpDomainRecord${G}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t.hostedZoneId,Name:M,Type:"A",AliasTarget:{DNSName:d.getAtt(L,"RegionalDomainName"),HostedZoneId:d.getAtt(L,"RegionalHostedZoneId")}}};R[`CustomDomain${G}`]={Description:`Custom domain ${M}`,Value:M},R[`CustomDomainTarget${G}`]={Description:`Point ${M} (CNAME/alias) at this APIGW regional domain`,Value:d.getAtt(L,"RegionalDomainName")}})}if(m)A.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${i}-${n}-dlq`,MessageRetentionPeriod:1209600}},l.forEach((N,M)=>{let G=`AppQueue${M}`,L=t.queueTimeout??120;A[G]={Type:"AWS::SQS::Queue",Properties:{QueueName:N.name,VisibilityTimeout:Math.min(43200,L*6),RedrivePolicy:{deadLetterTargetArn:d.getAtt("AppQueueDlq","Arn"),maxReceiveCount:t.queueTries??3}}};let oe=N.concurrency??t.queueConcurrency;A[`${G}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:d.getAtt(G,"Arn"),FunctionName:ge("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...oe?{ScalingConfig:{MaximumConcurrency:Math.max(2,oe)}}:{}}},R[`QueueUrl${M}`]={Description:`Queue URL: ${N.name}`,Value:d.ref(G)}});if(y)A.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${n}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:we("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},A.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ge("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:d.getAtt("SchedulerRule","Arn")}};if(t.warm&&t.warm>0){let M={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},G=(t.warmFunctions??["http"]).filter((L)=>L!=="queue"||m);for(let L of G){let oe=L.charAt(0).toUpperCase()+L.slice(1),Ft=Math.ceil(t.warm/5),Je=0;for(let Ie=0;Ie<Ft;Ie++){let Ye=Math.min(5,t.warm-Je);A[`Warmer${oe}Rule${Ie}`]={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${n}-warmer-${L}-${Ie}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Ye},(zn,ks)=>({Id:`warm-${L}-${Ie}-${ks}`,Arn:d.getAtt(M[L],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Je+=Ye}A[`Warmer${oe}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:d.ref(M[L]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:d.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${i}-${n}-warmer-${L}-*`)}}}}if(h)A.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${i}-${n}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},R.CacheTableName={Description:"DynamoDB cache table",Value:d.ref("CacheTable")};if(b){if(A.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:C,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},A.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${i}-${n}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},A.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:d.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:d.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...t.assetDomain?{Aliases:[t.assetDomain],ViewerCertificate:{AcmCertificateArn:t.assetCertificateArn??d.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},t.assetDomain){if(!t.assetCertificateArn){if(!t.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(o!=="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 ${o}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);A.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:t.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:t.assetDomain,HostedZoneId:t.hostedZoneId}]}}}if(t.hostedZoneId)A.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t.hostedZoneId,Name:t.assetDomain,Type:"A",AliasTarget:{DNSName:d.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};R.AssetDomain={Description:"Custom asset CDN host",Value:t.assetDomain}}A.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:d.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:d.sub(`arn:aws:s3:::${C}/*`),Condition:{StringEquals:{"AWS:SourceArn":d.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},R.AssetsBucketName={Description:"Assets bucket",Value:d.ref("AssetsBucket")},R.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:d.getAtt("AssetsDistribution","DomainName")}}if(t.firewall?.enabled){let N=[],M=0;if(t.firewall.rateLimit)N.push({Name:"rate-limit",Priority:M++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:t.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${n}-rate`}});let G={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let L of t.firewall.rules??[]){let oe=G[L];if(!oe)continue;N.push({Name:`managed-${L}`,Priority:M++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:oe}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${n}-${L}`}})}A.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${i}-${n}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:N,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${n}-waf`}}},R.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:d.getAtt("WebAcl","Arn")}}if(q&&F){if(!t.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.");A.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:t.vpc.id,GroupDescription:`${i}-${n} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(O)A.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${i}-${n}-efs`}]}},_.forEach((N,M)=>{A[`EfsMountTarget${M}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:d.ref("EfsFileSystem"),SubnetId:N,SecurityGroups:[d.getAtt("DataSecurityGroup","GroupId")]}}}),A.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:d.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},R.EfsFileSystemId={Description:"EFS file system id",Value:d.ref("EfsFileSystem")};if(t.cache?.driver==="elasticache")A.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${i}-${n} cache subnets`,SubnetIds:_}},A.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${i}-${n}-cache`,ReplicationGroupDescription:`${i}-${n} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),SecurityGroupIds:[d.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},R.CacheEndpoint={Description:"Redis primary endpoint",Value:d.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(t.database?.connection==="aurora-serverless")A.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${i}-${n} db subnets`,SubnetIds:_}},A.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${i}/${n}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},A.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${i}-${n}-db`,DatabaseName:"app",MasterUsername:d.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:d.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:t.database?.minCapacity??0.5,MaxCapacity:t.database?.maxCapacity??4},DBSubnetGroupName:d.ref("DbSubnetGroup"),VpcSecurityGroupIds:[d.getAtt("DataSecurityGroup","GroupId")]}},A.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:d.ref("DbCluster")}},R.DbEndpoint={Description:"Aurora cluster endpoint",Value:d.getAtt("DbCluster","Endpoint.Address")};if(t.rdsProxy&&t.database?.connection==="aurora-serverless")A.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:d.ref("DbSecret")}]}}]}},A.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof t.rdsProxy==="object"&&t.rdsProxy.name?t.rdsProxy.name:`${i}-${n}-proxy`,EngineFamily:"MYSQL",RoleArn:d.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:d.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:_,VpcSecurityGroupIds:[d.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},A.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:d.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[d.ref("DbCluster")]}},R.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:d.getAtt("DbProxy","Endpoint")};if(R.HttpFunctionName={Description:"HTTP function name",Value:d.ref("HttpFunction")},R.CliFunctionName={Description:"CLI function name",Value:d.ref("CliFunction")},m)R.QueueFunctionName={Description:"Queue function name",Value:d.ref("QueueFunction")};let $e={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${i}-${n})`,Parameters:g?{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:A,Outputs:R},Qe={};for(let N of Object.values(A))Qe[N.Type]=(Qe[N.Type]??0)+1;return{template:$e,functionNames:c,queueNames:u,resourceSummary:Qe}}var pl=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function gl(e){let t=`php${e.replace(".","")}`;return pl.map((n)=>`${t}-php-${n}`)}function Wn(e,t){let n=`php${e.replace(".","")}`,r=gl(e).join(" \\\n "),i=`/opt/remi/${n}/root`,s=`/etc/opt/remi/${n}`;return`${t?`FROM almalinux:9 AS ${t}`:"FROM almalinux:9"}
7264
7264
 
7265
7265
  # Build PHP on AlmaLinux 9 (where Remi's version-isolated SCL packages install
7266
7266
  # cleanly — Remi's release RPM rejects Amazon Linux 2023). AlmaLinux 9 shares
@@ -7321,7 +7321,7 @@ COPY app/ \${LAMBDA_TASK_ROOT}/
7321
7321
 
7322
7322
  # Per-function CMD (e.g. index.http) is supplied via ImageConfig.Command.
7323
7323
  CMD [ "index.http" ]
7324
- `}import{execFileSync as kt}from"node:child_process";import{mkdtempSync as ns,readFileSync as Mt,rmSync as rs}from"node:fs";import{tmpdir as is}from"node:os";import{dirname as yl,join as Re}from"node:path";import{fileURLToPath as fl}from"node:url";function ss(){return yl(fl(import.meta.url))}function as(){return Mt(Re(ss(),"runtime.mjs"),"utf-8")}function os(e){return Mt(Re(ss(),`${e}-bootstrap`),"utf-8")}function JA(e){let t=e.architecture??"x86_64",n=t==="arm64"?"arm64":"x64",r=e.version.replace(/^v/,""),i=e.onStep??(()=>{}),s=ns(Re(is(),"tscloud-node-layer-"));try{let a=r.includes(".")?r:hl(r),o=`node-v${a}-linux-${n}`,c=`https://nodejs.org/dist/v${a}/${o}.tar.xz`;i(`downloading Node ${a} (${t})`);let l=Re(s,"node.tar.xz");cs(c,l),i("extracting node binary"),kt("tar",["-xf",l,"-C",s,`${o}/bin/node`],{stdio:"inherit"});let u=Mt(Re(s,o,"bin","node"));i("packaging layer");let m=[{name:"bootstrap",data:os("node"),mode:493},{name:"runtime.mjs",data:as(),mode:420},{name:"bin/node",data:u,mode:493}];return{zip:he(m),architecture:t,version:a,fileCount:m.length}}finally{rs(s,{recursive:!0,force:!0})}}function YA(e){let t=e.architecture??"x86_64",n=t==="arm64"?"bun-linux-aarch64":"bun-linux-x64",r=e.version==="latest"?"":e.version.replace(/^v/,""),i=e.onStep??(()=>{}),s=ns(Re(is(),"tscloud-bun-layer-"));try{let a=r?`https://github.com/oven-sh/bun/releases/download/bun-v${r}/${n}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${n}.zip`;i(`downloading Bun ${r||"latest"} (${t})`);let o=Re(s,"bun.zip");cs(a,o),i("extracting bun binary"),kt("unzip",["-o","-q",o,"-d",s],{stdio:"inherit"});let c=Mt(Re(s,n,"bun"));i("packaging layer");let l=[{name:"bootstrap",data:os("bun"),mode:493},{name:"runtime.mjs",data:as(),mode:420},{name:"bin/bun",data:c,mode:493}];return{zip:he(l),architecture:t,version:r||"latest",fileCount:l.length}}finally{rs(s,{recursive:!0,force:!0})}}function cs(e,t){kt("curl",["-fsSL","-o",t,e],{stdio:["ignore","ignore","inherit"]})}function hl(e){let t=kt("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),r=JSON.parse(t).find((i)=>i.version.startsWith(`v${e}.`));if(!r)throw Error(`No Node release found for major version ${e}`);return r.version.replace(/^v/,"")}import{AsyncLocalStorage as vl}from"node:async_hooks";import{createHash as bl}from"node:crypto";var ls="x-ts-cloud-invoke-depth",us="x-ts-cloud-invoke-chain",ds="x-ts-cloud-trace-id";function Sl(e){return bl("sha256").update(e).digest("hex").slice(0,8)}var Lt={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function Vn(e,t){if(typeof e.get==="function")return e.get(t)??void 0;let n=e;return n[t]??n[t.toLowerCase()]??n[t.toUpperCase()]}function Al(e,t=64){if(!e)return[];return e.split(".").map((n)=>n.trim()).filter((n)=>/^[0-9a-f]{8}$/.test(n)).slice(-t)}function Cl(e,t=Lt){let n=Sl(e.functionId),r=Al(Vn(e.headers,us)),i=e.traceId??Vn(e.headers,ds)??crypto.randomUUID(),s=[...r,n],a=r.filter((m)=>m===n).length,o=r[r.length-1]===n,c=Number.parseInt(Vn(e.headers,ls)??"",10),l=Math.max(s.length,Number.isFinite(c)?c+1:0),u="ok";if(l>t.maxDepth)u="depth_exceeded";else if(a>=t.maxRepeats)u="cycle_detected";else if(o&&t.maxRepeats<=1)u="self_invocation";return{reason:u,depth:l,chain:s,traceId:i,selfInvocation:o,repeats:a,propagate:{[ls]:String(l),[us]:s.join("."),[ds]:i}}}var ms={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 Un{limits;clock;traces=new Map;breakers=new Map;constructor(e=Lt,t=()=>Date.now()){this.limits=e;this.clock=t}check(e){let t=this.clock();this.expireTraces(t);let n=Cl(e,this.limits),r=this.breakers.get(e.functionId);if(r?.openUntil!=null&&r.openUntil>t)return this.deny(e.functionId,n,"breaker_open",t,!1);if(n.reason!=="ok")return this.deny(e.functionId,n,n.reason,t,!0);let i=this.traces.get(n.traceId)??{count:0,firstAt:t};if(i.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(n.traceId,i),this.deny(e.functionId,n,"trace_budget_exceeded",t,!0);if(this.traces.set(n.traceId,{count:i.count+1,firstAt:i.firstAt}),r)this.breakers.set(e.functionId,{consecutiveBlocks:0});return{...n,allowed:!0,reason:"ok",propagate:n.propagate}}deny(e,t,n,r,i){if(i){let s=this.breakers.get(e)??{consecutiveBlocks:0},a=s.consecutiveBlocks+1;this.breakers.set(e,{consecutiveBlocks:a,openUntil:a>=this.limits.breakerThreshold?r+this.limits.breakerCooldownMs:s.openUntil})}return{...t,allowed:!1,reason:n,message:ms[n]}}breakerOpen(e){let t=this.breakers.get(e);return t?.openUntil!=null&&t.openUntil>this.clock()}reset(e){if(e){this.breakers.delete(e);return}this.breakers.clear(),this.traces.clear()}expireTraces(e){if(this.traces.size===0)return;for(let[t,n]of this.traces)if(e-n.firstAt>this.limits.traceWindowMs)this.traces.delete(t)}get trackedTraces(){return this.traces.size}}function ps(e){return{...e.propagate}}function gs(e){return{status:508,headers:{"content-type":"application/json","x-ts-cloud-recursion-blocked":e.reason},body:{error:"recursion_blocked",reason:e.reason,message:e.message??ms[e.reason],depth:e.depth,traceId:e.traceId}}}var fs=new vl;function ys(e){let t=globalThis.process?.env?.[e];if(t==null||t==="")return;return t!=="0"&&t.toLowerCase()!=="false"}function Tl(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function Rl(e){let t=e===!1?{enabled:!1}:e??{},n=ys("TS_CLOUD_RECURSION_PROTECTION"),r=ys("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:n??t.enabled??!0,detectionOnly:r??t.detectionOnly??!1,limits:{...Lt,...t.limits},functionId:t.functionId??Tl()}}var Me,be;function Pl(){let e=globalThis.fetch;if(!e||Me===e)return()=>{};be=e;let t=async(n,r)=>{let i=fs.getStore();if(!i)return be(n,r);let s=new Headers(r?.headers??(n instanceof Request?n.headers:void 0));for(let[a,o]of Object.entries(ps(i)))s.set(a,o);if(n instanceof Request)return be(new Request(n,{headers:s}),r);return be(n,{...r,headers:s})};return Object.assign(t,e),globalThis.fetch=t,Me=t,()=>{if(globalThis.fetch===Me&&be)globalThis.fetch=be;Me=void 0}}var Ot,Hn;function El(e){if(!Ot||JSON.stringify(Hn)!==JSON.stringify(e))Ot=new Un(e),Hn=e;return Ot}function rC(){if(Ot=void 0,Hn=void 0,Me&&be&&globalThis.fetch===Me)globalThis.fetch=be;Me=void 0,be=void 0}function hs(e,t){let n=Rl(t);if(!n.enabled)return;let r=El(n.limits),i={functionId:n.functionId,headers:e},s=r.check(i);return{verdict:s,blocked:!s.allowed&&!n.detectionOnly,observed:!s.allowed&&n.detectionOnly}}function bs(e,t){return Pl(),fs.run(e,t)}function oC(e){let t=e,n=t?.default??t;if(typeof n==="function")return{fetch:n};return{fetch:n?.fetch??t?.fetch,queue:n?.queue??t?.queue,cli:n?.cli??t?.cli}}var wl=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function Il(e){if(!e)return!0;return wl.test(e)}function Dl(e){if(e?.maintenance)return e.maintenance;let t=globalThis.process?.env??{};return{enabled:t.MAINTENANCE_MODE==="1"||t.MAINTENANCE_MODE==="true",bypassSecret:t.MAINTENANCE_BYPASS_SECRET}}function Nl(e){let t=e.requestContext?.domainName??"localhost",n=e.rawQueryString?`?${e.rawQueryString}`:"",r=`https://${t}${e.rawPath||"/"}${n}`,i=new Headers;for(let[o,c]of Object.entries(e.headers??{}))if(c!==void 0)i.set(o,c);if(e.cookies?.length)i.set("cookie",e.cookies.join("; "));let s=e.requestContext.http.method,a;if(e.body!==void 0&&s!=="GET"&&s!=="HEAD")a=e.isBase64Encoded?new Uint8Array(Buffer.from(e.body,"base64")):new TextEncoder().encode(e.body);return new Request(r,{method:s,headers:i,body:a})}async function Ss(e){let t={},n=[],r=typeof e.headers.getSetCookie==="function"?e.headers.getSetCookie():[];for(let a of r)n.push(a);e.headers.forEach((a,o)=>{if(o.toLowerCase()==="set-cookie")return;t[o]=a});let i=Buffer.from(await e.arrayBuffer()),s=Il(e.headers.get("content-type"));return{statusCode:e.status,headers:t,...n.length?{cookies:n}:{},body:s?i.toString("utf-8"):i.toString("base64"),isBase64Encoded:!s}}function xl(e,t){return async(n)=>{if(n.warmer)return{statusCode:200,headers:{"content-type":"text/plain"},body:"warm",isBase64Encoded:!1};if(!e)return{statusCode:501,headers:{"content-type":"text/plain"},body:"No HTTP handler configured",isBase64Encoded:!1};let r=Dl(t);if(r.enabled){let a=n.headers?.["x-maintenance-bypass"]??n.cookies?.find((o)=>o.startsWith("tscloud_bypass="))?.split("=")[1];if(!r.bypassSecret||a!==r.bypassSecret)return{statusCode:503,headers:{"content-type":"text/plain","retry-after":"120"},body:"Service temporarily unavailable (maintenance mode)",isBase64Encoded:!1}}let i=hs(n.headers??{},t?.recursionProtection);if(i?.blocked){let a=gs(i.verdict);return{statusCode:a.status,headers:{...a.headers,"retry-after":"60"},body:JSON.stringify(a.body),isBase64Encoded:!1}}let s=Nl(n);if(!i){let a=await e(s);return Ss(a)}if(i.observed)console.warn(`[ts-cloud] recursion detected (${i.verdict.reason}) at depth ${i.verdict.depth}; detection-only mode let it run`);return bs(i.verdict,async()=>Ss(await e(s)))}}function kl(e){try{return JSON.parse(e)}catch{return e}}function Ml(e){return async(t)=>{let n=[];if(t.warmer)return{batchItemFailures:n};if(!e)return{batchItemFailures:n};for(let r of t.Records??[])try{await e(kl(r.body),r)}catch{n.push({itemIdentifier:r.messageId})}return{batchItemFailures:n}}}function Ll(e){return async(t)=>{if(t.warmer)return{statusCode:0,output:"warm"};if(!e)return{statusCode:501,output:"No CLI handler configured"};return e(t)}}function cC(e,t){return{http:xl(e.fetch,t),queue:Ml(e.queue),cli:Ll(e.cli)}}function As(e={}){let t=e.socketPath??"/tmp/.tscloud-fpm.sock",n=e.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
7324
+ `}import{execFileSync as Mt}from"node:child_process";import{mkdtempSync as ns,readFileSync as Lt,rmSync as rs}from"node:fs";import{tmpdir as is}from"node:os";import{dirname as yl,join as Ee}from"node:path";import{fileURLToPath as fl}from"node:url";function ss(){return yl(fl(import.meta.url))}function as(){return Lt(Ee(ss(),"runtime.mjs"),"utf-8")}function os(e){return Lt(Ee(ss(),`${e}-bootstrap`),"utf-8")}function JA(e){let t=e.architecture??"x86_64",n=t==="arm64"?"arm64":"x64",r=e.version.replace(/^v/,""),i=e.onStep??(()=>{}),s=ns(Ee(is(),"tscloud-node-layer-"));try{let a=r.includes(".")?r:hl(r),o=`node-v${a}-linux-${n}`,c=`https://nodejs.org/dist/v${a}/${o}.tar.xz`;i(`downloading Node ${a} (${t})`);let l=Ee(s,"node.tar.xz");cs(c,l),i("extracting node binary"),Mt("tar",["-xf",l,"-C",s,`${o}/bin/node`],{stdio:"inherit"});let u=Lt(Ee(s,o,"bin","node"));i("packaging layer");let m=[{name:"bootstrap",data:os("node"),mode:493},{name:"runtime.mjs",data:as(),mode:420},{name:"bin/node",data:u,mode:493}];return{zip:Se(m),architecture:t,version:a,fileCount:m.length}}finally{rs(s,{recursive:!0,force:!0})}}function YA(e){let t=e.architecture??"x86_64",n=t==="arm64"?"bun-linux-aarch64":"bun-linux-x64",r=e.version==="latest"?"":e.version.replace(/^v/,""),i=e.onStep??(()=>{}),s=ns(Ee(is(),"tscloud-bun-layer-"));try{let a=r?`https://github.com/oven-sh/bun/releases/download/bun-v${r}/${n}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${n}.zip`;i(`downloading Bun ${r||"latest"} (${t})`);let o=Ee(s,"bun.zip");cs(a,o),i("extracting bun binary"),Mt("unzip",["-o","-q",o,"-d",s],{stdio:"inherit"});let c=Lt(Ee(s,n,"bun"));i("packaging layer");let l=[{name:"bootstrap",data:os("bun"),mode:493},{name:"runtime.mjs",data:as(),mode:420},{name:"bin/bun",data:c,mode:493}];return{zip:Se(l),architecture:t,version:r||"latest",fileCount:l.length}}finally{rs(s,{recursive:!0,force:!0})}}function cs(e,t){Mt("curl",["-fsSL","-o",t,e],{stdio:["ignore","ignore","inherit"]})}function hl(e){let t=Mt("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),r=JSON.parse(t).find((i)=>i.version.startsWith(`v${e}.`));if(!r)throw Error(`No Node release found for major version ${e}`);return r.version.replace(/^v/,"")}import{AsyncLocalStorage as vl}from"node:async_hooks";import{createHash as bl}from"node:crypto";var ls="x-ts-cloud-invoke-depth",us="x-ts-cloud-invoke-chain",ds="x-ts-cloud-trace-id";function Sl(e){return bl("sha256").update(e).digest("hex").slice(0,8)}var Ot={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function Vn(e,t){if(typeof e.get==="function")return e.get(t)??void 0;let n=e;return n[t]??n[t.toLowerCase()]??n[t.toUpperCase()]}function Al(e,t=64){if(!e)return[];return e.split(".").map((n)=>n.trim()).filter((n)=>/^[0-9a-f]{8}$/.test(n)).slice(-t)}function Cl(e,t=Ot){let n=Sl(e.functionId),r=Al(Vn(e.headers,us)),i=e.traceId??Vn(e.headers,ds)??crypto.randomUUID(),s=[...r,n],a=r.filter((m)=>m===n).length,o=r[r.length-1]===n,c=Number.parseInt(Vn(e.headers,ls)??"",10),l=Math.max(s.length,Number.isFinite(c)?c+1:0),u="ok";if(l>t.maxDepth)u="depth_exceeded";else if(a>=t.maxRepeats)u="cycle_detected";else if(o&&t.maxRepeats<=1)u="self_invocation";return{reason:u,depth:l,chain:s,traceId:i,selfInvocation:o,repeats:a,propagate:{[ls]:String(l),[us]:s.join("."),[ds]:i}}}var ms={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 Un{limits;clock;traces=new Map;breakers=new Map;constructor(e=Ot,t=()=>Date.now()){this.limits=e;this.clock=t}check(e){let t=this.clock();this.expireTraces(t);let n=Cl(e,this.limits),r=this.breakers.get(e.functionId);if(r?.openUntil!=null&&r.openUntil>t)return this.deny(e.functionId,n,"breaker_open",t,!1);if(n.reason!=="ok")return this.deny(e.functionId,n,n.reason,t,!0);let i=this.traces.get(n.traceId)??{count:0,firstAt:t};if(i.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(n.traceId,i),this.deny(e.functionId,n,"trace_budget_exceeded",t,!0);if(this.traces.set(n.traceId,{count:i.count+1,firstAt:i.firstAt}),r)this.breakers.set(e.functionId,{consecutiveBlocks:0});return{...n,allowed:!0,reason:"ok",propagate:n.propagate}}deny(e,t,n,r,i){if(i){let s=this.breakers.get(e)??{consecutiveBlocks:0},a=s.consecutiveBlocks+1;this.breakers.set(e,{consecutiveBlocks:a,openUntil:a>=this.limits.breakerThreshold?r+this.limits.breakerCooldownMs:s.openUntil})}return{...t,allowed:!1,reason:n,message:ms[n]}}breakerOpen(e){let t=this.breakers.get(e);return t?.openUntil!=null&&t.openUntil>this.clock()}reset(e){if(e){this.breakers.delete(e);return}this.breakers.clear(),this.traces.clear()}expireTraces(e){if(this.traces.size===0)return;for(let[t,n]of this.traces)if(e-n.firstAt>this.limits.traceWindowMs)this.traces.delete(t)}get trackedTraces(){return this.traces.size}}function ps(e){return{...e.propagate}}function gs(e){return{status:508,headers:{"content-type":"application/json","x-ts-cloud-recursion-blocked":e.reason},body:{error:"recursion_blocked",reason:e.reason,message:e.message??ms[e.reason],depth:e.depth,traceId:e.traceId}}}var fs=new vl;function ys(e){let t=globalThis.process?.env?.[e];if(t==null||t==="")return;return t!=="0"&&t.toLowerCase()!=="false"}function Tl(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function Rl(e){let t=e===!1?{enabled:!1}:e??{},n=ys("TS_CLOUD_RECURSION_PROTECTION"),r=ys("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:n??t.enabled??!0,detectionOnly:r??t.detectionOnly??!1,limits:{...Ot,...t.limits},functionId:t.functionId??Tl()}}var Le,Ae;function Pl(){let e=globalThis.fetch;if(!e||Le===e)return()=>{};Ae=e;let t=async(n,r)=>{let i=fs.getStore();if(!i)return Ae(n,r);let s=new Headers(r?.headers??(n instanceof Request?n.headers:void 0));for(let[a,o]of Object.entries(ps(i)))s.set(a,o);if(n instanceof Request)return Ae(new Request(n,{headers:s}),r);return Ae(n,{...r,headers:s})};return Object.assign(t,e),globalThis.fetch=t,Le=t,()=>{if(globalThis.fetch===Le&&Ae)globalThis.fetch=Ae;Le=void 0}}var $t,Hn;function El(e){if(!$t||JSON.stringify(Hn)!==JSON.stringify(e))$t=new Un(e),Hn=e;return $t}function rC(){if($t=void 0,Hn=void 0,Le&&Ae&&globalThis.fetch===Le)globalThis.fetch=Ae;Le=void 0,Ae=void 0}function hs(e,t){let n=Rl(t);if(!n.enabled)return;let r=El(n.limits),i={functionId:n.functionId,headers:e},s=r.check(i);return{verdict:s,blocked:!s.allowed&&!n.detectionOnly,observed:!s.allowed&&n.detectionOnly}}function bs(e,t){return Pl(),fs.run(e,t)}function oC(e){let t=e,n=t?.default??t;if(typeof n==="function")return{fetch:n};return{fetch:n?.fetch??t?.fetch,queue:n?.queue??t?.queue,cli:n?.cli??t?.cli}}var wl=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function Il(e){if(!e)return!0;return wl.test(e)}function Dl(e){if(e?.maintenance)return e.maintenance;let t=globalThis.process?.env??{};return{enabled:t.MAINTENANCE_MODE==="1"||t.MAINTENANCE_MODE==="true",bypassSecret:t.MAINTENANCE_BYPASS_SECRET}}function Nl(e){let t=e.requestContext?.domainName??"localhost",n=e.rawQueryString?`?${e.rawQueryString}`:"",r=`https://${t}${e.rawPath||"/"}${n}`,i=new Headers;for(let[o,c]of Object.entries(e.headers??{}))if(c!==void 0)i.set(o,c);if(e.cookies?.length)i.set("cookie",e.cookies.join("; "));let s=e.requestContext.http.method,a;if(e.body!==void 0&&s!=="GET"&&s!=="HEAD")a=e.isBase64Encoded?new Uint8Array(Buffer.from(e.body,"base64")):new TextEncoder().encode(e.body);return new Request(r,{method:s,headers:i,body:a})}async function Ss(e){let t={},n=[],r=typeof e.headers.getSetCookie==="function"?e.headers.getSetCookie():[];for(let a of r)n.push(a);e.headers.forEach((a,o)=>{if(o.toLowerCase()==="set-cookie")return;t[o]=a});let i=Buffer.from(await e.arrayBuffer()),s=Il(e.headers.get("content-type"));return{statusCode:e.status,headers:t,...n.length?{cookies:n}:{},body:s?i.toString("utf-8"):i.toString("base64"),isBase64Encoded:!s}}function xl(e,t){return async(n)=>{if(n.warmer)return{statusCode:200,headers:{"content-type":"text/plain"},body:"warm",isBase64Encoded:!1};if(!e)return{statusCode:501,headers:{"content-type":"text/plain"},body:"No HTTP handler configured",isBase64Encoded:!1};let r=Dl(t);if(r.enabled){let a=n.headers?.["x-maintenance-bypass"]??n.cookies?.find((o)=>o.startsWith("tscloud_bypass="))?.split("=")[1];if(!r.bypassSecret||a!==r.bypassSecret)return{statusCode:503,headers:{"content-type":"text/plain","retry-after":"120"},body:"Service temporarily unavailable (maintenance mode)",isBase64Encoded:!1}}let i=hs(n.headers??{},t?.recursionProtection);if(i?.blocked){let a=gs(i.verdict);return{statusCode:a.status,headers:{...a.headers,"retry-after":"60"},body:JSON.stringify(a.body),isBase64Encoded:!1}}let s=Nl(n);if(!i){let a=await e(s);return Ss(a)}if(i.observed)console.warn(`[ts-cloud] recursion detected (${i.verdict.reason}) at depth ${i.verdict.depth}; detection-only mode let it run`);return bs(i.verdict,async()=>Ss(await e(s)))}}function kl(e){try{return JSON.parse(e)}catch{return e}}function Ml(e){return async(t)=>{let n=[];if(t.warmer)return{batchItemFailures:n};if(!e)return{batchItemFailures:n};for(let r of t.Records??[])try{await e(kl(r.body),r)}catch{n.push({itemIdentifier:r.messageId})}return{batchItemFailures:n}}}function Ll(e){return async(t)=>{if(t.warmer)return{statusCode:0,output:"warm"};if(!e)return{statusCode:501,output:"No CLI handler configured"};return e(t)}}function cC(e,t){return{http:xl(e.fetch,t),queue:Ml(e.queue),cli:Ll(e.cli)}}function As(e={}){let t=e.socketPath??"/tmp/.tscloud-fpm.sock",n=e.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
7325
7325
  [global]
7326
7326
  daemonize = no
7327
7327
  error_log = ${e.errorLog??"/tmp/storage/logs/php-fpm.log"}
@@ -7338,4 +7338,4 @@ decorate_workers_output = no
7338
7338
  php_admin_value[error_log] = /dev/stderr
7339
7339
  php_admin_flag[log_errors] = on
7340
7340
  clear_env = no
7341
- `}import{readFileSync as Ol}from"node:fs";import{dirname as $l,join as Cs}from"node:path";import{fileURLToPath as Bl}from"node:url";function Fl(){return Cs($l(Bl(import.meta.url)),"runtime-assets")}function jn(){let e=Fl(),t=(n)=>Ol(Cs(e,n),"utf-8");return[{path:"bootstrap",contents:t("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:t("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:t("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:t("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:t("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:As(),mode:420}]}function EC(e={}){let t=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:t,CACHE_DRIVER:t,SESSION_DRIVER:t,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 vs=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];import{execFileSync as $t}from"node:child_process";import{existsSync as Gl,mkdirSync as _l,mkdtempSync as Wl,readdirSync as Vl,readFileSync as Ul,rmSync as Hl,statSync as Ts,writeFileSync as jl}from"node:fs";import{tmpdir as Kl}from"node:os";import{join as Ke,relative as ql}from"node:path";function*Rs(e){for(let t of Vl(e)){let n=Ke(e,t);if(Ts(n).isDirectory())yield*Rs(n);else yield n}}function OC(e={}){let t=e.architecture??"x86_64",n=e.platform??(t==="arm64"?"linux/arm64":"linux/amd64"),r=e.onStep??(()=>{}),i=Wl(Ke(Kl(),"tscloud-php-layer-")),s="tscloud-php-layer:build";try{jl(Ke(i,"Dockerfile"),ts(e)),r("Building PHP runtime image (docker)"),$t("docker",["build","--platform",n,"-t","tscloud-php-layer:build",i],{stdio:"inherit"}),r("Extracting /opt/php from image");let a=$t("docker",["create","--platform",n,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),o=Ke(i,"opt");_l(o,{recursive:!0});try{$t("docker",["cp",`${a}:/opt/php`,Ke(o,"php")],{stdio:"inherit"})}finally{$t("docker",["rm",a],{stdio:"ignore"})}if(!Gl(Ke(o,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let c=[];for(let p of Rs(o)){let g=ql(o,p).replace(/\\/g,"/"),y=Ts(p).mode&73?493:420;c.push({name:g,data:Ul(p),mode:y})}r("Injecting runtime assets");let l=new Set(jn().map((p)=>p.path)),u=c.filter((p)=>!l.has(p.name));for(let p of jn())u.push({name:p.path,data:p.contents,mode:p.mode});return r("Packaging layer ZIP"),{zip:he(u),architecture:t,fileCount:u.length}}finally{Hl(i,{recursive:!0,force:!0})}}import{execSync as zl}from"node:child_process";import{createHash as Ql}from"node:crypto";import{readdirSync as Jl,readFileSync as Yl,statSync as Ps}from"node:fs";import{join as Zl,relative as Es,resolve as Kn}from"node:path";var Xl=[".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 eu(e,t){return t.some((n)=>e===n||e.startsWith(`${n}/`))}function*ws(e,t,n){for(let r of Jl(e)){let i=Zl(e,r),s=Es(t,i).replace(/\\/g,"/");if(eu(s,n))continue;if(Ps(i).isDirectory())yield*ws(i,t,n);else yield i}}function tu(e){if(e.skipBuild)return;let t=Kn(e.projectRoot??process.cwd()),n=e.app.build??vs;for(let r of n)e.onStep?.(`build: ${r}`),zl(r,{stdio:"inherit",cwd:t})}function nu(e,t=[]){let n=Kn(e),r=[...Xl,$e(),...t],i=[];for(let s of ws(n,n,r)){let a=Es(n,s).replace(/\\/g,"/"),o=(Ps(s).mode&73)!==0;i.push({name:a,data:Yl(s),mode:o?493:420})}return i}function HC(e){let t=Kn(e.projectRoot??process.cwd());tu(e),e.onStep?.("packaging application tree");let n=nu(t,e.exclude);if(!n.length)throw Error(`No files to package under ${t}`);let r=he(n),i=e.app.handlers?.http??"public/index.php";return{zip:r,sha256:Ql("sha256").update(r).digest("hex"),handlers:{http:i,queue:e.app.handlers?.queue??i,cli:e.app.handlers?.cli??i},fileCount:n.length}}class Is{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let t=`asset-opt-${Date.now()}-${this.counter++}`,n={id:t,...e};return this.optimizations.set(t,n),n}createImageOptimization(e){let t=`image-opt-${Date.now()}-${this.counter++}`,n={id:t,...e};return this.imageConfigs.set(t,n),n}createSSGConfig(e){let t=`ssg-${Date.now()}-${this.counter++}`,n={id:t,...e};return this.ssgConfigs.set(t,n),n}createPrerenderConfig(e){let t=`prerender-${Date.now()}-${this.counter++}`,n={id:t,...e};return this.prerenderConfigs.set(t,n),n}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 ZC=new Is;class qn{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(e,t){let n=`lifecycle-${Date.now()}-${this.counter++}`,r={id:n,transitions:e,expiration:t};return this.policies.set(n,r),r}enableVersioning(e=!1){let t=`versioning-${Date.now()}-${this.counter++}`,n={id:t,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(t,n),n}createReplicationRule(e,t,n){let r=`replication-${Date.now()}-${this.counter++}`,i={id:r,sourceRegion:e,destRegion:t,destBucket:n};return this.replicationRules.set(r,i),i}createIntelligentTiering(e,t){let n=`tiering-${Date.now()}-${this.counter++}`,r={id:n,archiveDays:e,deepArchiveDays:t};return this.tieringConfigs.set(n,r),r}enableObjectLock(e){let t=`object-lock-${Date.now()}-${this.counter++}`,n={id:t,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(t,n),n}enableTransferAcceleration(e){let t=`transfer-accel-${Date.now()}-${this.counter++}`,n={id:t,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(t,n),n}createAccessPoint(e){let t=`access-point-${Date.now()}-${this.counter++}`,n={id:t,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(t,n),n}createGlacierArchive(e){let t=`glacier-${Date.now()}-${this.counter++}`,n={id:t,bucketName:e.bucketName,archiveType:e.archiveType,transitionDays:e.transitionDays,restoreConfig:e.restoreTier?{tier:e.restoreTier,days:e.restoreDays||7}:void 0};return this.glacierConfigs.set(t,n),n}createInventory(e){let t=`inventory-${Date.now()}-${this.counter++}`,n={id:t,sourceBucket:e.sourceBucket,destinationBucket:e.destinationBucket,schedule:e.schedule||"Daily",format:e.format||"CSV",includedFields:e.includedFields||["Size","LastModifiedDate","StorageClass","ETag"],prefix:e.prefix};return this.inventories.set(t,n),n}createBatchOperation(e){let t=`batch-op-${Date.now()}-${this.counter++}`,n={id:t,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(t,n),n}executeBatchOperation(e){let t=this.batchOps.get(e);if(!t)throw Error(`Batch operation not found: ${e}`);return t.status="in_progress",t.totalObjects=1000,t.processedObjects=0,t}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let t=`event-${Date.now()}-${this.counter++}`,n={id:t,bucketName:e.bucketName,events:e.events,destination:{type:"Lambda",arn:e.lambdaArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(t,n),n}createSQSNotification(e){let t=`event-${Date.now()}-${this.counter++}`,n={id:t,bucketName:e.bucketName,events:e.events,destination:{type:"SQS",arn:e.queueArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(t,n),n}createSNSNotification(e){let t=`event-${Date.now()}-${this.counter++}`,n={id:t,bucketName:e.bucketName,events:e.events,destination:{type:"SNS",arn:e.topicArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(t,n),n}generateObjectLockCF(e){let t={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)t.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)t.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return t}generateTransferAccelerationCF(e){return{AccelerateConfiguration:{AccelerationStatus:e.enabled?"Enabled":"Suspended"}}}generateAccessPointCF(e){return{Type:"AWS::S3::AccessPoint",Properties:{Name:e.name,Bucket:e.bucketName,...e.vpcId&&{VpcConfiguration:{VpcId:e.vpcId}},PublicAccessBlockConfiguration:e.publicAccessBlock?{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}:void 0,...e.policy&&{Policy:e.policy}}}}generateInventoryCF(e){return{Type:"AWS::S3::Bucket",Properties:{InventoryConfigurations:[{Id:e.id,Destination:{BucketArn:`arn:aws:s3:::${e.destinationBucket}`,Format:e.format},Enabled:!0,IncludedObjectVersions:"Current",OptionalFields:e.includedFields,ScheduleFrequency:e.schedule,...e.prefix&&{Prefix:e.prefix}}]}}}generateEventNotificationCF(e){let t=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",n=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",r={Event:e.events[0],[n]:e.destination.arn};if(e.filter)r.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[t]:[r]}}}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 ru=new qn;class Ds{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,t=30,n=10){let r=`health-${Date.now()}-${this.counter++}`,i={id:r,url:e,interval:t,timeout:n,status:"healthy"};return this.checks.set(r,i),i}createSyntheticMonitor(e,t,n,r){let i=`synthetic-${Date.now()}-${this.counter++}`,s={id:i,name:e,script:t,frequency:n,locations:r};return this.synthetics.set(i,s),s}trackUptime(e,t,n){let r=`uptime-${Date.now()}-${this.counter++}`,i=t/(t+n)*100,s={id:r,resource:e,uptime:t,downtime:n,availability:i};return this.uptimeTrackers.set(r,s),s}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var tv=new Ds;class Ns{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,t,n,r){let i=`waf-${Date.now()}-${this.counter++}`,s={id:i,name:e,priority:t,action:n,conditions:r};return this.wafRules.set(i,s),s}enableShield(e,t="standard"){let n=`shield-${Date.now()}-${this.counter++}`,r={id:n,resourceArn:e,protectionType:t};return this.shieldProtections.set(n,r),r}createSecurityGroup(e,t,n){let r=`sg-${Date.now()}-${this.counter++}`,i={id:r,name:e,vpcId:t,rules:n};return this.securityGroups.set(r,i),i}createNACL(e,t){let n=`nacl-${Date.now()}-${this.counter++}`,r={id:n,vpcId:e,rules:t};return this.nacls.set(n,r),r}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var rv=new Ns;class xs{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,t){let n=`tagging-${Date.now()}-${this.counter++}`,r={id:n,tags:e,resources:t};return this.strategies.set(n,r),r}createCostAllocation(e,t){let n=`cost-${Date.now()}-${this.counter++}`,r={id:n,tagKey:e,allocations:t};return this.allocations.set(n,r),r}createResourceGroup(e,t,n){let r=`group-${Date.now()}-${this.counter++}`,i={id:r,name:e,query:{resourceTypeFilters:t,tagFilters:n}};return this.groups.set(r,i),i}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var sv=new xs;export{Cn as ABTestManager,ht as AI,Vo as AWSAPIError,hn as AWSConfigManager,fp as AWS_PSEUDO_PARAMETERS,le as AWS_REGIONS,wa as ApiGateway,Fe as Arn,H as AssetHasher,Y as Auth,yn as BackupManager,Ji as BatchProcessingManager,An as BlueGreenManager,_i as BounceComplaintHandler,xi as BuildOptimizationManager,ie as CDN,us as CHAIN_HEADER,Vt as CLOUDFRONT_FAILOVER_STATUS_CODES,wh as COMMON_CROSS_ACCOUNT_ROLES,Ea as Cache,mt as CanaryManager,Ii as CertificateManager,fe as CloudError,Mr as CloudFormationBuilder,Do as CloudFormationClient,_o as CloudFrontClient,bn as CloudTrailManager,Cc as CommandHistory,X as Communication,x as Compute,It as ConfigurationError,En as ContainerRegistryManager,ve as CredentialError,fi as CrossRegionReferenceManager,oo as DASHBOARD_ENTRY,uo as DASHBOARD_PORT_BASE,mo as DASHBOARD_PORT_SPAN,ao as DASHBOARD_STATE_DIR,tr as DEFAULT_FAILOVER_STATUS_CODES,Lt as DEFAULT_RECURSION_LIMITS,ee as DEFAULT_SERVICE_LIMITS,_t as DEFAULT_STATE_DIR,da as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,ls as DEPTH_HEADER,Qi as DLQMonitoringManager,Q as DNS,Fi as DNSSECManager,zt as Database,Ei as DatabaseUserManager,z as DebugLogger,aa as DependencyGraph,Z as Deployment,Wo as DeploymentError,fn as DisasterRecoveryManager,G as Email,Hi as EmailAdvanced,Wi as EmailAnalyticsManager,ji as EmailHandlers,Ui as EmailTemplateManager,Uo as ErrorCodes,pa as FAILOVER_REPLICA_POLICY_SID,zi as FIFOQueueManager,on as FileCache,Xe as FileSystem,d as Fn,hi as GlobalResourceManager,Sn as GuardDutyManager,Xo as HashCache,Ds as HealthCheckManager,Ni as ImageScanningManager,Ce as JobLoader,vs as LARAVEL_SERVERLESS_BUILD_STEPS,Li as LambdaConcurrencyManager,Bi as LambdaDLQManager,Oi as LambdaDestinationsManager,ki as LambdaLayersManager,$i as LambdaVPCManager,Mi as LambdaVersionsManager,Tn as LogsManager,dl as MANAGED_NODE_VERSIONS,Br as MANAGEMENT_DASHBOARD_SITE_PREFIX,te as Messaging,Ti as MetricsManager,Ri as MigrationManager,li as MockCloudFormation,di as MockDynamoDB,ui as MockS3,fr as Monitoring,Ai as MultiAccountManager,yi as MultiRegionManager,pc as MultiStepProgress,B as Network,Ns as NetworkSecurityManager,ir as ORIGIN_CONNECTION_ATTEMPTS,sr as ORIGIN_CONNECTION_TIMEOUT,nr as ORIGIN_GROUP_ALLOWED_METHODS,ed as ORIGIN_GROUP_ID_SUFFIX,rr as ORIGIN_GROUP_SELECTION_CRITERIA,Ci as OrganizationManager,Xl as PHP_DEFAULT_EXCLUDES,pl as PHP_LAYER_EXTENSIONS,_ as ParameterStore,Pi as PerformanceManager,ce as Permissions,ye as Phone,Ki as PhoneAdvanced,ur as PhoneHandlers,mn as PreviewEnvironmentManager,pn as PreviewNotificationService,mc as ProgressBar,vn as ProgressiveDeploymentManager,sa as Pseudo,oe as Queue,Yi as QueueManagementManager,au as QueuePresets,Pc as RECOMMENDED_ACCOUNT_STRUCTURES,Eh as RECOMMENDED_SCPS,bc as REPL,Ac as REPLCommandBuilder,Sc as REPLContext,ec as RateLimiter,ou as RealtimePresets,Un as RecursionGuard,At as Redirects,bi as RegionPairManager,pe as Registry,Rn as ReplicaManager,xs as ResourceManagementManager,Gi as Route53ResolverManager,In as Route53RoutingManager,rn as S3Client,q as S3Error,J as SMS,Qn as STATE_DIR_ENV_VAR,ma as STORAGE_FAILOVER_METADATA_KEY,nt as Search,tt as Secrets,Pn as SecretsManager,wi as SecretsRotationManager,W as Security,Ne as SecurityHubManager,Di as SecurityScanningManager,Vi as SenderReputationManager,wn as ServiceMeshManager,Pa as Sftp,qi as SmsAdvanced,yr as SmsHandlers,gc as Spinner,Si as StackDependencyManager,_d as StacksIntegration,Is as StaticSiteManager,Ie as Storage,qn as StorageAdvancedManager,xe as SyntheticsManager,ds as TRACE_HEADER,yc as TaskList,Ks as TemplateBuilder,cn as TemplateCache,ti as ValidationError,Ia as Workflow,vi as XRayManager,Lc as abTestManager,lr as amazonLinuxImageId,ha as amazonLinuxImageParameter,Hu as analyzeStackDiff,NA as artifactKey,Ht as assertOriginGroupMethods,Gf as autocomplete,Ic as awsConfigManager,Ec as backupManager,qy as batch,uA as batchProcessingManager,kc as blueGreenManager,dS as bounceComplaintHandler,YA as buildBunRuntimeLayerZip,tg as buildCloudFormationTemplate,md as buildFailoverReplicaPolicyStatement,Au as buildMailEnv,JA as buildNodeRuntimeLayerZip,Hb as buildOptimizationManager,Ut as buildOriginGroup,td as buildOriginGroups,OC as buildPhpRuntimeLayerZip,dd as buildReplicationConfiguration,ud as buildReplicationRole,Mc as canaryManager,rf as categorizeChanges,Fb as certificateManager,Ry as checkIAMPermissions,hs as checkInvocation,Iy as checkServiceQuotas,tc as chunk,Xg as clearSigningKeyCache,ic as cloudConfigSchema,Dc as cloudTrailManager,nu as collectPhpAppEntries,_g as composePresets,FA as composeServerlessAppTemplate,_c as containerRegistryManager,yg as createApiBackendPreset,Ll as createCliHandler,oy as createCredentialProvider,Og as createDashboardSite,Pg as createDataPipelinePreset,ei as createError,mg as createExistingStaticFullStackPreset,pg as createFullStackAppPreset,cC as createHandlers,xl as createHttpHandler,Sg as createJamstackPreset,xg as createLaravelPreset,wg as createMLApiPreset,Cg as createMicroservicesPreset,hf as createMockAWS,sg as createNodeJsServerPreset,og as createNodeJsServerlessPreset,Wg as createPreset,Vr as createPresignedUrl,Qg as createPresignedUrlAsync,Ml as createQueueHandler,Tg as createRealtimeAppPreset,Go as createS3Client,Mg as createServerlessLaravelPreset,lg as createServerlessNodePreset,rg as createStaticSitePreset,Dg as createTraditionalWebAppPreset,hg as createWordPressPreset,he as createZip,rh as crossRegionReferenceManager,Mb as databaseUserManager,ci as defaultLocalConfig,yu as deploymentCoexistenceError,po as deriveManagementDashboardPort,Yn as detectDeploymentTargets,Sy as detectMisconfigurations,_r as detectServiceRegion,ef as diffTemplates,cA as dlqMonitoringManager,oS as dnssecManager,wc as drManager,pS as emailAnalyticsManager,hS as emailTemplateManager,Nl as eventToRequest,Fr as extendPreset,aA as fifoQueueManager,jy as findChangedFiles,xh as formatAccountStructure,Df as formatBytes,ju as formatDiff,Nf as formatDuration,Wf as formatFlagSuggestions,Kf as formatHistory,qf as formatHistoryStats,kf as formatKeyValue,xf as formatList,If as formatProgressBar,Rc as formatRegion,fh as formatRegionList,Of as formatSuggestion,Ef as formatTable,wf as formatTree,Po as fromEC2Metadata,Eo as fromECSMetadata,vo as fromEnvironment,To as fromSharedCredentials,wo as fromWebIdentity,Sl as functionFingerprint,VA as generateAppImageDockerfile,Yh as generateApprovalConfig,Zi as generateBootstrap,oc as generateCleanupWorkflow,cc as generateCostReportWorkflow,Dh as generateCrossAccountRoleCF,zh as generateDeploymentConfig,Vh as generateDeploymentPipeline,$h as generateDeploymentWorkflow,f as generateLogicalId,Kh as generateManualPipeline,_h as generateMatrixWorkflow,Qh as generateMultiEnvConfig,Uh as generateMultiEnvPipeline,Bh as generateMultiEnvWorkflow,Fh as generatePRPreviewWorkflow,Zh as generateParallelConfig,As as generatePhpFpmConfig,ts as generatePhpLayerDockerfile,Hh as generatePreviewPipeline,ac as generatePreviewWorkflow,S as generateResourceName,Jh as generateScheduledConfig,jh as generateScheduledPipeline,Gh as generateScheduledWorkflow,Zr as getAccountId,ch as getAllRegions,ph as getClosestRegion,Vf as getCommandUsage,Bf as getContextualHelp,ct as getCredentials,sf as getDeploymentStrategy,af as getDiffStats,tf as getDiffSummary,Ho as getErrorDetails,dn as getLocalConfig,gf as getLocalCredentials,pf as getLocalEndpoint,yf as getLocalEnvVars,Dy as getQuotaUsageSummary,Ih as getRecommendedStructure,ut as getRegion,hh as getRegionStats,uh as getRegionsByCompliance,lh as getRegionsByLocation,dh as getRegionsByPricingTier,jo as getRequiredPermissions,ey as getSigningKeyCacheSize,xu as getTimestamp,ih as globalResourceManager,Nc as guardDutyManager,fo as hasManagementDashboardSite,Wy as hashBuffer,Vy as hashDirectory,si as hashFile,Uy as hashManifest,ai as hashString,tv as healthCheckManager,Vb as imageScanningManager,Cl as inspectInvocation,Pl as installRecursionFetch,fs as invocationContext,fa as isArmInstanceType,$f as isLikelyTypo,mf as isLocalDevelopment,ho as isManagementDashboardSiteName,ty as isNodeCryptoAvailable,or as isS3RestEndpoint,du as isStateDirConfigured,mu as isStatePath,mh as isValidRegion,ny as isWebCryptoAvailable,Zb as lambdaConcurrencyManager,iS as lambdaDLQManager,eS as lambdaDestinationsManager,zb as lambdaLayersManager,nS as lambdaVPCManager,Jb as lambdaVersionsManager,EC as laravelServerlessEnvDefaults,$c as logsManager,Vs as mailEnabled,Su as mailFirewallPorts,Cu as mailWebmailSites,De as makeAWSRequest,Yg as makeAWSRequestAsync,Jg as makeAWSRequestOnce,Lr as managementDashboardSiteName,Ge as mergeInfrastructure,Rb as metricsManager,Ib as migrationManager,Th as multiAccountManager,th as multiRegionManager,rv as networkSecurityManager,Rh as organizationManager,HC as packagePhpApp,xA as packageServerlessApp,un as parallel,zy as parallelMap,Qy as parallelWithRetry,Al as parseChain,Zg as parseJSONResponse,wt as parseXMLResponse,xb as performanceManager,Wn as phpLayerBuildStage,gl as phpLayerPackages,jn as phpRuntimeLayerAssets,sc as previewManager,lc as previewNotifications,Zy as processInChunks,Oc as progressiveDeploymentManager,ps as propagationHeaders,mA as queueManagementManager,Hy as quickHash,gs as recursionBlockedResponse,sh as regionPairManager,Fc as replicaManager,nf as requiresReplacement,rC as resetRecursionRuntime,oC as resolveApp,hu as resolveAppDatabase,Ru as resolveCloudProvider,Ue as resolveCredentials,go as resolveDashboardDomain,yo as resolveDashboardDomains,Gu as resolveDeployBucketName,gu as resolveDeploymentMode,ft as resolveFailoverStatusCodes,vu as resolveMailProxy,js as resolveMailService,Fg as resolveManagementDashboardSite,bo as resolveManagementDashboardSites,Be as resolveOriginConnection,Lu as resolveProjectStackName,BA as resolveQueueNames,es as resolveQueues,Rl as resolveRecursionConfig,Io as resolveRegion,_u as resolveServerlessAppStackName,Wu as resolveServerlessArtifactBucketName,Xn as resolveServerlessAssetBucketName,Xi as resolveServerlessRuntime,Bu as resolveSiteBucketName,$u as resolveSiteResourceName,Ou as resolveSiteStackName,_s as resolveStatePath,Fu as resolveStorageBucketName,cd as resolveStorageFailover,sv as resourceManagementManager,Ss as responseToResult,lS as route53ResolverManager,Vc as route53RoutingManager,ll as runBuildHooks,tu as runPhpBuildHooks,ld as s3RegionalDomain,ku as sanitizeName,Ff as searchCommands,Gc as secretsManager,Ob as secretsRotationManager,xc as securityHubManager,_b as securityScanningManager,yS as senderReputationManager,Jy as sequence,Wc as serviceMeshManager,uu as setStateDir,ul as sha256,El as sharedRecursionGuard,as as sharedRuntimeLoop,V as signRequest,Wr as signRequestAsync,ah as stackDependencyManager,$e as stateDir,Jn as statePath,ZC as staticSiteManager,ru as storageAdvancedManager,pd as storageFailoverReplicasFromTemplate,gi as suggestCommand,_f as suggestFlags,Py as suggestIAMPolicy,Ny as suggestQuotaIncrease,yh as suggestRegionPairs,gh as suggestRegions,Bc as syntheticsManager,zo as templateCache,Nh as validateAccountStructure,uf as validateAgainstSchema,Uf as validateCommand,by as validateConfiguration,Ty as validateCredentials,cr as validateOriginGroups,ia as validateResourceLimits,qs as validateTemplate,ra as validateTemplateSize,Kg as withCDN,jg as withCache,Hg as withDatabase,bs as withInvocation,Vg as withMonitoring,qg as withQueue,Ug as withSecurity,Yy as withTimeout,vb as xrayManager};
7341
+ `}import{readFileSync as Ol}from"node:fs";import{dirname as $l,join as Cs}from"node:path";import{fileURLToPath as Bl}from"node:url";function Fl(){return Cs($l(Bl(import.meta.url)),"runtime-assets")}function jn(){let e=Fl(),t=(n)=>Ol(Cs(e,n),"utf-8");return[{path:"bootstrap",contents:t("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:t("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:t("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:t("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:t("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:As(),mode:420}]}function EC(e={}){let t=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:t,CACHE_DRIVER:t,SESSION_DRIVER:t,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 vs=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];import{execFileSync as Bt}from"node:child_process";import{existsSync as Gl,mkdirSync as _l,mkdtempSync as Wl,readdirSync as Vl,readFileSync as Ul,rmSync as Hl,statSync as Ts,writeFileSync as jl}from"node:fs";import{tmpdir as Kl}from"node:os";import{join as ze,relative as ql}from"node:path";function*Rs(e){for(let t of Vl(e)){let n=ze(e,t);if(Ts(n).isDirectory())yield*Rs(n);else yield n}}function OC(e={}){let t=e.architecture??"x86_64",n=e.platform??(t==="arm64"?"linux/arm64":"linux/amd64"),r=e.onStep??(()=>{}),i=Wl(ze(Kl(),"tscloud-php-layer-")),s="tscloud-php-layer:build";try{jl(ze(i,"Dockerfile"),ts(e)),r("Building PHP runtime image (docker)"),Bt("docker",["build","--platform",n,"-t","tscloud-php-layer:build",i],{stdio:"inherit"}),r("Extracting /opt/php from image");let a=Bt("docker",["create","--platform",n,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),o=ze(i,"opt");_l(o,{recursive:!0});try{Bt("docker",["cp",`${a}:/opt/php`,ze(o,"php")],{stdio:"inherit"})}finally{Bt("docker",["rm",a],{stdio:"ignore"})}if(!Gl(ze(o,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let c=[];for(let p of Rs(o)){let g=ql(o,p).replace(/\\/g,"/"),y=Ts(p).mode&73?493:420;c.push({name:g,data:Ul(p),mode:y})}r("Injecting runtime assets");let l=new Set(jn().map((p)=>p.path)),u=c.filter((p)=>!l.has(p.name));for(let p of jn())u.push({name:p.path,data:p.contents,mode:p.mode});return r("Packaging layer ZIP"),{zip:Se(u),architecture:t,fileCount:u.length}}finally{Hl(i,{recursive:!0,force:!0})}}import{execSync as zl}from"node:child_process";import{createHash as Ql}from"node:crypto";import{readdirSync as Jl,readFileSync as Yl,statSync as Ps}from"node:fs";import{join as Zl,relative as Es,resolve as Kn}from"node:path";var Xl=[".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 eu(e,t){return t.some((n)=>e===n||e.startsWith(`${n}/`))}function*ws(e,t,n){for(let r of Jl(e)){let i=Zl(e,r),s=Es(t,i).replace(/\\/g,"/");if(eu(s,n))continue;if(Ps(i).isDirectory())yield*ws(i,t,n);else yield i}}function tu(e){if(e.skipBuild)return;let t=Kn(e.projectRoot??process.cwd()),n=e.app.build??vs;for(let r of n)e.onStep?.(`build: ${r}`),zl(r,{stdio:"inherit",cwd:t})}function nu(e,t=[]){let n=Kn(e),r=[...Xl,Fe(),...t],i=[];for(let s of ws(n,n,r)){let a=Es(n,s).replace(/\\/g,"/"),o=(Ps(s).mode&73)!==0;i.push({name:a,data:Yl(s),mode:o?493:420})}return i}function HC(e){let t=Kn(e.projectRoot??process.cwd());tu(e),e.onStep?.("packaging application tree");let n=nu(t,e.exclude);if(!n.length)throw Error(`No files to package under ${t}`);let r=Se(n),i=e.app.handlers?.http??"public/index.php";return{zip:r,sha256:Ql("sha256").update(r).digest("hex"),handlers:{http:i,queue:e.app.handlers?.queue??i,cli:e.app.handlers?.cli??i},fileCount:n.length}}class Is{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let t=`asset-opt-${Date.now()}-${this.counter++}`,n={id:t,...e};return this.optimizations.set(t,n),n}createImageOptimization(e){let t=`image-opt-${Date.now()}-${this.counter++}`,n={id:t,...e};return this.imageConfigs.set(t,n),n}createSSGConfig(e){let t=`ssg-${Date.now()}-${this.counter++}`,n={id:t,...e};return this.ssgConfigs.set(t,n),n}createPrerenderConfig(e){let t=`prerender-${Date.now()}-${this.counter++}`,n={id:t,...e};return this.prerenderConfigs.set(t,n),n}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 ZC=new Is;class qn{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(e,t){let n=`lifecycle-${Date.now()}-${this.counter++}`,r={id:n,transitions:e,expiration:t};return this.policies.set(n,r),r}enableVersioning(e=!1){let t=`versioning-${Date.now()}-${this.counter++}`,n={id:t,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(t,n),n}createReplicationRule(e,t,n){let r=`replication-${Date.now()}-${this.counter++}`,i={id:r,sourceRegion:e,destRegion:t,destBucket:n};return this.replicationRules.set(r,i),i}createIntelligentTiering(e,t){let n=`tiering-${Date.now()}-${this.counter++}`,r={id:n,archiveDays:e,deepArchiveDays:t};return this.tieringConfigs.set(n,r),r}enableObjectLock(e){let t=`object-lock-${Date.now()}-${this.counter++}`,n={id:t,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(t,n),n}enableTransferAcceleration(e){let t=`transfer-accel-${Date.now()}-${this.counter++}`,n={id:t,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(t,n),n}createAccessPoint(e){let t=`access-point-${Date.now()}-${this.counter++}`,n={id:t,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(t,n),n}createGlacierArchive(e){let t=`glacier-${Date.now()}-${this.counter++}`,n={id:t,bucketName:e.bucketName,archiveType:e.archiveType,transitionDays:e.transitionDays,restoreConfig:e.restoreTier?{tier:e.restoreTier,days:e.restoreDays||7}:void 0};return this.glacierConfigs.set(t,n),n}createInventory(e){let t=`inventory-${Date.now()}-${this.counter++}`,n={id:t,sourceBucket:e.sourceBucket,destinationBucket:e.destinationBucket,schedule:e.schedule||"Daily",format:e.format||"CSV",includedFields:e.includedFields||["Size","LastModifiedDate","StorageClass","ETag"],prefix:e.prefix};return this.inventories.set(t,n),n}createBatchOperation(e){let t=`batch-op-${Date.now()}-${this.counter++}`,n={id:t,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(t,n),n}executeBatchOperation(e){let t=this.batchOps.get(e);if(!t)throw Error(`Batch operation not found: ${e}`);return t.status="in_progress",t.totalObjects=1000,t.processedObjects=0,t}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let t=`event-${Date.now()}-${this.counter++}`,n={id:t,bucketName:e.bucketName,events:e.events,destination:{type:"Lambda",arn:e.lambdaArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(t,n),n}createSQSNotification(e){let t=`event-${Date.now()}-${this.counter++}`,n={id:t,bucketName:e.bucketName,events:e.events,destination:{type:"SQS",arn:e.queueArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(t,n),n}createSNSNotification(e){let t=`event-${Date.now()}-${this.counter++}`,n={id:t,bucketName:e.bucketName,events:e.events,destination:{type:"SNS",arn:e.topicArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(t,n),n}generateObjectLockCF(e){let t={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)t.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)t.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return t}generateTransferAccelerationCF(e){return{AccelerateConfiguration:{AccelerationStatus:e.enabled?"Enabled":"Suspended"}}}generateAccessPointCF(e){return{Type:"AWS::S3::AccessPoint",Properties:{Name:e.name,Bucket:e.bucketName,...e.vpcId&&{VpcConfiguration:{VpcId:e.vpcId}},PublicAccessBlockConfiguration:e.publicAccessBlock?{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}:void 0,...e.policy&&{Policy:e.policy}}}}generateInventoryCF(e){return{Type:"AWS::S3::Bucket",Properties:{InventoryConfigurations:[{Id:e.id,Destination:{BucketArn:`arn:aws:s3:::${e.destinationBucket}`,Format:e.format},Enabled:!0,IncludedObjectVersions:"Current",OptionalFields:e.includedFields,ScheduleFrequency:e.schedule,...e.prefix&&{Prefix:e.prefix}}]}}}generateEventNotificationCF(e){let t=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",n=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",r={Event:e.events[0],[n]:e.destination.arn};if(e.filter)r.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[t]:[r]}}}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 ru=new qn;class Ds{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,t=30,n=10){let r=`health-${Date.now()}-${this.counter++}`,i={id:r,url:e,interval:t,timeout:n,status:"healthy"};return this.checks.set(r,i),i}createSyntheticMonitor(e,t,n,r){let i=`synthetic-${Date.now()}-${this.counter++}`,s={id:i,name:e,script:t,frequency:n,locations:r};return this.synthetics.set(i,s),s}trackUptime(e,t,n){let r=`uptime-${Date.now()}-${this.counter++}`,i=t/(t+n)*100,s={id:r,resource:e,uptime:t,downtime:n,availability:i};return this.uptimeTrackers.set(r,s),s}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var tv=new Ds;class Ns{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,t,n,r){let i=`waf-${Date.now()}-${this.counter++}`,s={id:i,name:e,priority:t,action:n,conditions:r};return this.wafRules.set(i,s),s}enableShield(e,t="standard"){let n=`shield-${Date.now()}-${this.counter++}`,r={id:n,resourceArn:e,protectionType:t};return this.shieldProtections.set(n,r),r}createSecurityGroup(e,t,n){let r=`sg-${Date.now()}-${this.counter++}`,i={id:r,name:e,vpcId:t,rules:n};return this.securityGroups.set(r,i),i}createNACL(e,t){let n=`nacl-${Date.now()}-${this.counter++}`,r={id:n,vpcId:e,rules:t};return this.nacls.set(n,r),r}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var rv=new Ns;class xs{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,t){let n=`tagging-${Date.now()}-${this.counter++}`,r={id:n,tags:e,resources:t};return this.strategies.set(n,r),r}createCostAllocation(e,t){let n=`cost-${Date.now()}-${this.counter++}`,r={id:n,tagKey:e,allocations:t};return this.allocations.set(n,r),r}createResourceGroup(e,t,n){let r=`group-${Date.now()}-${this.counter++}`,i={id:r,name:e,query:{resourceTypeFilters:t,tagFilters:n}};return this.groups.set(r,i),i}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var sv=new xs;export{Cn as ABTestManager,bt as AI,Vo as AWSAPIError,hn as AWSConfigManager,fp as AWS_PSEUDO_PARAMETERS,ue as AWS_REGIONS,wa as ApiGateway,_e as Arn,j as AssetHasher,Z as Auth,yn as BackupManager,Ji as BatchProcessingManager,An as BlueGreenManager,_i as BounceComplaintHandler,xi as BuildOptimizationManager,se as CDN,us as CHAIN_HEADER,Vt as CLOUDFRONT_FAILOVER_STATUS_CODES,wh as COMMON_CROSS_ACCOUNT_ROLES,Ea as Cache,pt as CanaryManager,Ii as CertificateManager,be as CloudError,Mr as CloudFormationBuilder,Do as CloudFormationClient,_o as CloudFrontClient,bn as CloudTrailManager,Cc as CommandHistory,ee as Communication,x as Compute,Dt as ConfigurationError,En as ContainerRegistryManager,Re as CredentialError,fi as CrossRegionReferenceManager,oo as DASHBOARD_ENTRY,uo as DASHBOARD_PORT_BASE,mo as DASHBOARD_PORT_SPAN,ao as DASHBOARD_STATE_DIR,tr as DEFAULT_FAILOVER_STATUS_CODES,Ot as DEFAULT_RECURSION_LIMITS,te as DEFAULT_SERVICE_LIMITS,_t as DEFAULT_STATE_DIR,da as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,ls as DEPTH_HEADER,Qi as DLQMonitoringManager,J as DNS,Fi as DNSSECManager,zt as Database,Ei as DatabaseUserManager,Q as DebugLogger,aa as DependencyGraph,X as Deployment,Wo as DeploymentError,fn as DisasterRecoveryManager,W as Email,Hi as EmailAdvanced,Wi as EmailAnalyticsManager,ji as EmailHandlers,Ui as EmailTemplateManager,Uo as ErrorCodes,pa as FAILOVER_REPLICA_POLICY_SID,zi as FIFOQueueManager,on as FileCache,et as FileSystem,d as Fn,hi as GlobalResourceManager,Sn as GuardDutyManager,Xo as HashCache,Ds as HealthCheckManager,Ni as ImageScanningManager,Te as JobLoader,vs as LARAVEL_SERVERLESS_BUILD_STEPS,Li as LambdaConcurrencyManager,Bi as LambdaDLQManager,Oi as LambdaDestinationsManager,ki as LambdaLayersManager,$i as LambdaVPCManager,Mi as LambdaVersionsManager,Tn as LogsManager,dl as MANAGED_NODE_VERSIONS,Br as MANAGEMENT_DASHBOARD_SITE_PREFIX,re as Messaging,Ti as MetricsManager,Ri as MigrationManager,li as MockCloudFormation,di as MockDynamoDB,ui as MockS3,fr as Monitoring,Ai as MultiAccountManager,yi as MultiRegionManager,pc as MultiStepProgress,B as Network,Ns as NetworkSecurityManager,ir as ORIGIN_CONNECTION_ATTEMPTS,sr as ORIGIN_CONNECTION_TIMEOUT,nr as ORIGIN_GROUP_ALLOWED_METHODS,ed as ORIGIN_GROUP_ID_SUFFIX,rr as ORIGIN_GROUP_SELECTION_CRITERIA,Ci as OrganizationManager,Xl as PHP_DEFAULT_EXCLUDES,pl as PHP_LAYER_EXTENSIONS,V as ParameterStore,Pi as PerformanceManager,le as Permissions,he as Phone,Ki as PhoneAdvanced,ur as PhoneHandlers,mn as PreviewEnvironmentManager,pn as PreviewNotificationService,mc as ProgressBar,vn as ProgressiveDeploymentManager,sa as Pseudo,ce as Queue,Yi as QueueManagementManager,au as QueuePresets,Pc as RECOMMENDED_ACCOUNT_STRUCTURES,Eh as RECOMMENDED_SCPS,bc as REPL,Ac as REPLCommandBuilder,Sc as REPLContext,ec as RateLimiter,ou as RealtimePresets,Un as RecursionGuard,Ct as Redirects,bi as RegionPairManager,ye as Registry,Rn as ReplicaManager,xs as ResourceManagementManager,Gi as Route53ResolverManager,In as Route53RoutingManager,rn as S3Client,z as S3Error,Y as SMS,Qn as STATE_DIR_ENV_VAR,ma as STORAGE_FAILOVER_METADATA_KEY,rt as Search,nt as Secrets,Pn as SecretsManager,wi as SecretsRotationManager,U as Security,xe as SecurityHubManager,Di as SecurityScanningManager,Vi as SenderReputationManager,wn as ServiceMeshManager,Pa as Sftp,qi as SmsAdvanced,yr as SmsHandlers,gc as Spinner,Si as StackDependencyManager,_d as StacksIntegration,Is as StaticSiteManager,De as Storage,qn as StorageAdvancedManager,ke as SyntheticsManager,ds as TRACE_HEADER,yc as TaskList,Ks as TemplateBuilder,cn as TemplateCache,ti as ValidationError,Ia as Workflow,vi as XRayManager,Lc as abTestManager,lr as amazonLinuxImageId,ha as amazonLinuxImageParameter,Hu as analyzeStackDiff,NA as artifactKey,Ht as assertOriginGroupMethods,Gf as autocomplete,Ic as awsConfigManager,Ec as backupManager,qy as batch,uA as batchProcessingManager,kc as blueGreenManager,dS as bounceComplaintHandler,YA as buildBunRuntimeLayerZip,tg as buildCloudFormationTemplate,md as buildFailoverReplicaPolicyStatement,Au as buildMailEnv,JA as buildNodeRuntimeLayerZip,Hb as buildOptimizationManager,Ut as buildOriginGroup,td as buildOriginGroups,OC as buildPhpRuntimeLayerZip,dd as buildReplicationConfiguration,ud as buildReplicationRole,Mc as canaryManager,rf as categorizeChanges,Fb as certificateManager,Ry as checkIAMPermissions,hs as checkInvocation,Iy as checkServiceQuotas,tc as chunk,Xg as clearSigningKeyCache,ic as cloudConfigSchema,Dc as cloudTrailManager,nu as collectPhpAppEntries,_g as composePresets,FA as composeServerlessAppTemplate,_c as containerRegistryManager,yg as createApiBackendPreset,Ll as createCliHandler,oy as createCredentialProvider,Og as createDashboardSite,Pg as createDataPipelinePreset,ei as createError,mg as createExistingStaticFullStackPreset,pg as createFullStackAppPreset,cC as createHandlers,xl as createHttpHandler,Sg as createJamstackPreset,xg as createLaravelPreset,wg as createMLApiPreset,Cg as createMicroservicesPreset,hf as createMockAWS,sg as createNodeJsServerPreset,og as createNodeJsServerlessPreset,Wg as createPreset,Vr as createPresignedUrl,Qg as createPresignedUrlAsync,Ml as createQueueHandler,Tg as createRealtimeAppPreset,Go as createS3Client,Mg as createServerlessLaravelPreset,lg as createServerlessNodePreset,rg as createStaticSitePreset,Dg as createTraditionalWebAppPreset,hg as createWordPressPreset,Se as createZip,rh as crossRegionReferenceManager,Mb as databaseUserManager,ci as defaultLocalConfig,yu as deploymentCoexistenceError,po as deriveManagementDashboardPort,Yn as detectDeploymentTargets,Sy as detectMisconfigurations,_r as detectServiceRegion,ef as diffTemplates,cA as dlqMonitoringManager,oS as dnssecManager,wc as drManager,pS as emailAnalyticsManager,hS as emailTemplateManager,Nl as eventToRequest,Fr as extendPreset,aA as fifoQueueManager,jy as findChangedFiles,xh as formatAccountStructure,Df as formatBytes,ju as formatDiff,Nf as formatDuration,Wf as formatFlagSuggestions,Kf as formatHistory,qf as formatHistoryStats,kf as formatKeyValue,xf as formatList,If as formatProgressBar,Rc as formatRegion,fh as formatRegionList,Of as formatSuggestion,Ef as formatTable,wf as formatTree,Po as fromEC2Metadata,Eo as fromECSMetadata,vo as fromEnvironment,To as fromSharedCredentials,wo as fromWebIdentity,Sl as functionFingerprint,VA as generateAppImageDockerfile,Yh as generateApprovalConfig,Zi as generateBootstrap,oc as generateCleanupWorkflow,cc as generateCostReportWorkflow,Dh as generateCrossAccountRoleCF,zh as generateDeploymentConfig,Vh as generateDeploymentPipeline,$h as generateDeploymentWorkflow,f as generateLogicalId,Kh as generateManualPipeline,_h as generateMatrixWorkflow,Qh as generateMultiEnvConfig,Uh as generateMultiEnvPipeline,Bh as generateMultiEnvWorkflow,Fh as generatePRPreviewWorkflow,Zh as generateParallelConfig,As as generatePhpFpmConfig,ts as generatePhpLayerDockerfile,Hh as generatePreviewPipeline,ac as generatePreviewWorkflow,S as generateResourceName,Jh as generateScheduledConfig,jh as generateScheduledPipeline,Gh as generateScheduledWorkflow,Zr as getAccountId,ch as getAllRegions,ph as getClosestRegion,Vf as getCommandUsage,Bf as getContextualHelp,lt as getCredentials,sf as getDeploymentStrategy,af as getDiffStats,tf as getDiffSummary,Ho as getErrorDetails,dn as getLocalConfig,gf as getLocalCredentials,pf as getLocalEndpoint,yf as getLocalEnvVars,Dy as getQuotaUsageSummary,Ih as getRecommendedStructure,dt as getRegion,hh as getRegionStats,uh as getRegionsByCompliance,lh as getRegionsByLocation,dh as getRegionsByPricingTier,jo as getRequiredPermissions,ey as getSigningKeyCacheSize,xu as getTimestamp,ih as globalResourceManager,Nc as guardDutyManager,fo as hasManagementDashboardSite,Wy as hashBuffer,Vy as hashDirectory,si as hashFile,Uy as hashManifest,ai as hashString,tv as healthCheckManager,Vb as imageScanningManager,Cl as inspectInvocation,Pl as installRecursionFetch,fs as invocationContext,fa as isArmInstanceType,$f as isLikelyTypo,mf as isLocalDevelopment,ho as isManagementDashboardSiteName,ty as isNodeCryptoAvailable,or as isS3RestEndpoint,du as isStateDirConfigured,mu as isStatePath,mh as isValidRegion,ny as isWebCryptoAvailable,Zb as lambdaConcurrencyManager,iS as lambdaDLQManager,eS as lambdaDestinationsManager,zb as lambdaLayersManager,nS as lambdaVPCManager,Jb as lambdaVersionsManager,EC as laravelServerlessEnvDefaults,$c as logsManager,Vs as mailEnabled,Su as mailFirewallPorts,Cu as mailWebmailSites,Ne as makeAWSRequest,Yg as makeAWSRequestAsync,Jg as makeAWSRequestOnce,Lr as managementDashboardSiteName,We as mergeInfrastructure,Rb as metricsManager,Ib as migrationManager,Th as multiAccountManager,th as multiRegionManager,rv as networkSecurityManager,Rh as organizationManager,HC as packagePhpApp,xA as packageServerlessApp,un as parallel,zy as parallelMap,Qy as parallelWithRetry,Al as parseChain,Zg as parseJSONResponse,It as parseXMLResponse,xb as performanceManager,Wn as phpLayerBuildStage,gl as phpLayerPackages,jn as phpRuntimeLayerAssets,sc as previewManager,lc as previewNotifications,Zy as processInChunks,Oc as progressiveDeploymentManager,ps as propagationHeaders,mA as queueManagementManager,Hy as quickHash,gs as recursionBlockedResponse,sh as regionPairManager,Fc as replicaManager,nf as requiresReplacement,rC as resetRecursionRuntime,oC as resolveApp,hu as resolveAppDatabase,Ru as resolveCloudProvider,je as resolveCredentials,go as resolveDashboardDomain,yo as resolveDashboardDomains,Gu as resolveDeployBucketName,gu as resolveDeploymentMode,ht as resolveFailoverStatusCodes,vu as resolveMailProxy,js as resolveMailService,Fg as resolveManagementDashboardSite,bo as resolveManagementDashboardSites,Ge as resolveOriginConnection,Lu as resolveProjectStackName,BA as resolveQueueNames,es as resolveQueues,Rl as resolveRecursionConfig,Io as resolveRegion,_u as resolveServerlessAppStackName,Wu as resolveServerlessArtifactBucketName,Xn as resolveServerlessAssetBucketName,Xi as resolveServerlessRuntime,Bu as resolveSiteBucketName,$u as resolveSiteResourceName,Ou as resolveSiteStackName,_s as resolveStatePath,Fu as resolveStorageBucketName,cd as resolveStorageFailover,sv as resourceManagementManager,Ss as responseToResult,lS as route53ResolverManager,Vc as route53RoutingManager,ll as runBuildHooks,tu as runPhpBuildHooks,ld as s3RegionalDomain,ku as sanitizeName,Ff as searchCommands,Gc as secretsManager,Ob as secretsRotationManager,xc as securityHubManager,_b as securityScanningManager,yS as senderReputationManager,Jy as sequence,Wc as serviceMeshManager,uu as setStateDir,ul as sha256,El as sharedRecursionGuard,as as sharedRuntimeLoop,H as signRequest,Wr as signRequestAsync,ah as stackDependencyManager,Fe as stateDir,Jn as statePath,ZC as staticSiteManager,ru as storageAdvancedManager,pd as storageFailoverReplicasFromTemplate,gi as suggestCommand,_f as suggestFlags,Py as suggestIAMPolicy,Ny as suggestQuotaIncrease,yh as suggestRegionPairs,gh as suggestRegions,Bc as syntheticsManager,zo as templateCache,Nh as validateAccountStructure,uf as validateAgainstSchema,Uf as validateCommand,by as validateConfiguration,Ty as validateCredentials,cr as validateOriginGroups,ia as validateResourceLimits,qs as validateTemplate,ra as validateTemplateSize,Kg as withCDN,jg as withCache,Hg as withDatabase,bs as withInvocation,Vg as withMonitoring,qg as withQueue,Ug as withSecurity,Yy as withTimeout,vb as xrayManager};