@ts-cloud/core 0.16.16 → 0.16.18
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 +143 -143
- package/dist/modules/cdn-failover.d.ts +81 -1
- package/dist/modules/cdn.d.ts +15 -7
- package/dist/modules/index.d.ts +1 -0
- package/dist/modules/storage-failover.d.ts +99 -0
- package/dist/template-builder.d.ts +4 -0
- package/dist/types.d.ts +175 -5
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import{createRequire as
|
|
2
|
-
`),O=
|
|
3
|
-
`),j=e.cache??
|
|
4
|
-
`),le=await
|
|
5
|
-
`),ne=e.cache??
|
|
6
|
-
`,P=
|
|
7
|
-
`),E=[
|
|
8
|
-
`),w=
|
|
9
|
-
`,P=
|
|
10
|
-
`),E=[
|
|
11
|
-
`),w=await
|
|
1
|
+
import{createRequire as $s}from"node:module";var ks=Object.defineProperty;var Ms=(e)=>e;function Ls(e,t){this[e]=Ms.bind(null,t)}var Oe=(e,t)=>{for(var n in t)ks(e,n,{get:t[n],enumerable:!0,configurable:!0,set:Ls.bind(t,n)})};var Os=(e,t,n)=>()=>{if(e)try{t=e(e=0)}catch(r){n=[r]}if(n)throw n[0];return t};var Bs=$s(import.meta.url);function Gr(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=yo[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=Gr(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 f=l||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),b=f.substring(0,8),v=[b,y,g,"aws4_request"].join("/"),T="AWS4-HMAC-SHA256";if(o)return ho({urlObj:u,method:t,body:r,accessKeyId:i,secretAccessKey:s,sessionToken:a,service:g,region:y,timestamp:f,date:b,credentialScope:v,algorithm:T,expiresIn:c,cache:e.cache});let A=u.pathname||"/",P=Pt(u.searchParams),R={host:m,"x-amz-date":f,...e.headers};if(a)R["x-amz-security-token"]=a;let E=Object.keys(R).some((Pe)=>Pe.toLowerCase()==="content-type");if(r&&!E)R["content-type"]="application/x-amz-json-1.0";if(g==="s3"&&!R["x-amz-content-sha256"])R["x-amz-content-sha256"]=st(r);let D=Vr(R),w=Ur(R),N=R["x-amz-content-sha256"]||st(r),k=[t,Et(A),P,D,w,N].join(`
|
|
2
|
+
`),O=st(k),le=[T,f,v,O].join(`
|
|
3
|
+
`),j=e.cache??We,ne=jr(s,b,y,g,le,j),U=[`${T} Credential=${i}/${v}`,`SignedHeaders=${w}`,`Signature=${ne}`].join(", ");return R.authorization=U,{url:n,method:t,headers:R,body:r||void 0}}async function _r(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=Gr(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 f=l||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),b=f.substring(0,8),v=[b,y,g,"aws4_request"].join("/"),T="AWS4-HMAC-SHA256";if(o)return fo({urlObj:u,method:t,body:r,accessKeyId:i,secretAccessKey:s,sessionToken:a,service:g,region:y,timestamp:f,date:b,credentialScope:v,algorithm:T,expiresIn:c,cache:e.cache});let A=u.pathname||"/",P=Pt(u.searchParams),R={host:m,"x-amz-date":f,...e.headers};if(a)R["x-amz-security-token"]=a;let E=Object.keys(R).some((qe)=>qe.toLowerCase()==="content-type");if(r&&!E)R["content-type"]="application/x-amz-json-1.0";let D=await vt(r);if(g==="s3"&&!R["x-amz-content-sha256"])R["x-amz-content-sha256"]=D;let w=Vr(R),N=Ur(R),k=R["x-amz-content-sha256"]||D,O=[t,Et(A),P,w,N,k].join(`
|
|
4
|
+
`),le=await vt(O),j=[T,f,v,le].join(`
|
|
5
|
+
`),ne=e.cache??We,U=await Kr(s,b,y,g,j,ne),Pe=[`${T} Credential=${i}/${v}`,`SignedHeaders=${N}`,`Signature=${U}`].join(", ");return R.authorization=Pe,{url:n,method:t,headers:R,body:r||void 0}}function ho(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,f=new URL(t.toString());f.searchParams.set("X-Amz-Algorithm",p),f.searchParams.set("X-Amz-Credential",`${i}/${m}`),f.searchParams.set("X-Amz-Date",l),f.searchParams.set("X-Amz-Expires",String(g));let b=o==="s3"?"UNSIGNED-PAYLOAD":st(r);if(o==="s3")f.searchParams.set("X-Amz-Content-Sha256",b);let v="host";if(f.searchParams.set("X-Amz-SignedHeaders",v),a)f.searchParams.set("X-Amz-Security-Token",a);let T=Et(f.pathname||"/"),A=`host:${f.hostname}
|
|
6
|
+
`,P=Pt(f.searchParams),R=[n,T,P,A,v,b].join(`
|
|
7
|
+
`),E=[p,l,m,st(R)].join(`
|
|
8
|
+
`),w=jr(s,u,c,o,E,y??We);return f.searchParams.set("X-Amz-Signature",w),{url:f.toString(),method:n,headers:{},body:r||void 0}}async function fo(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,f=new URL(t.toString());f.searchParams.set("X-Amz-Algorithm",p),f.searchParams.set("X-Amz-Credential",`${i}/${m}`),f.searchParams.set("X-Amz-Date",l),f.searchParams.set("X-Amz-Expires",String(g));let b=o==="s3"?"UNSIGNED-PAYLOAD":await vt(r);if(o==="s3")f.searchParams.set("X-Amz-Content-Sha256",b);let v="host";if(f.searchParams.set("X-Amz-SignedHeaders",v),a)f.searchParams.set("X-Amz-Security-Token",a);let T=Et(f.pathname||"/"),A=`host:${f.hostname}
|
|
9
|
+
`,P=Pt(f.searchParams),R=[n,T,P,A,v,b].join(`
|
|
10
|
+
`),E=[p,l,m,await vt(R)].join(`
|
|
11
|
+
`),w=await Kr(s,u,c,o,E,y??We);return f.searchParams.set("X-Amz-Signature",w),{url:f.toString(),method:n,headers:{},body:r||void 0}}function Wr(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 Hg(e){let{url:t,method:n="GET",expiresIn:r=3600,...i}=e,s=Math.min(r,604800);return(await _r({...i,url:t,method:n,signQuery:!0,expiresIn:s})).url}function Vr(e){return Object.keys(e).sort().map((t)=>`${t.toLowerCase()}:${e[t].trim().replace(/\s+/g," ")}`).join(`
|
|
12
12
|
`)+`
|
|
13
|
-
`}function Mr(e){return Object.keys(e).sort().map((t)=>t.toLowerCase()).join(";")}function At(e){let t=[];return e.forEach((n,r)=>{t.push([qt(r),qt(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 Ct(e){return e.split("/").map((t)=>qt(t)).join("/")}function qt(e){return encodeURIComponent(e).replace(/[!'()*]/g,(t)=>`%${t.charCodeAt(0).toString(16).toUpperCase()}`)}function nt(e){if(!Fe)throw Error("Synchronous hash not available in browser. Use signRequestAsync() instead.");return Fe.createHash("sha256").update(e,"utf8").digest("hex")}function et(e,t){if(!Fe)throw Error("Synchronous hmac not available in browser. Use signRequestAsync() instead.");return Fe.createHmac("sha256",e).update(t,"utf8").digest()}async function ft(e){let n=new TextEncoder().encode(e),r=await crypto.subtle.digest("SHA-256",n);return Lr(new Uint8Array(r))}async function tt(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 Lr(e){return Array.from(e).map((t)=>t.toString(16).padStart(2,"0")).join("")}function Or(e,t,n,r,i,s){let a=`${e}:${t}:${n}:${r}`,o=s.get(a);if(!o){let c=et(`AWS4${e}`,t),l=et(c,n),u=et(l,r);if(o=et(u,"aws4_request"),s.size>=Ir){let p=s.keys().next().value;if(p)s.delete(p)}s.set(a,o)}return et(o,i).toString("hex")}async function $r(e,t,n,r,i,s){let a=`${e}:${t}:${n}:${r}`,o=s.get(a);if(!o){let l=await tt(`AWS4${e}`,t),u=await tt(l,n),p=await tt(u,r);if(o=await tt(p,"aws4_request"),s.size>=Ir){let m=s.keys().next().value;if(m)s.delete(m)}s.set(a,o)}let c=await tt(o,i);return Lr(c)}function Br(e,t){return t.includes(e)}function bt(e,t,n){let r=t*Math.pow(2,e),i=Math.random()*0.3*r;return Math.min(r+i,n)}function St(e){return new Promise((t)=>setTimeout(t,e))}async function Ie(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),p={method:u.method,headers:u.headers};if(u.body)p.body=u.body;let m=new AbortController,g=setTimeout(()=>m.abort(),a);p.signal=m.signal;try{let y=await fetch(u.url,p);if(clearTimeout(g),c=y,y.ok)return y;if(l<n&&Br(y.status,s)){let S=bt(l,r,i);await St(S);continue}let f=await y.text();throw Error(`AWS API request failed (${y.status}): ${f}`)}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 f=bt(l,r,i);await St(f);continue}throw o}}throw o??Error("Request failed after retries")}async function Cg(e){return Ie(e,{maxRetries:0})}async function vg(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 Nr(e),u={method:l.method,headers:l.headers};if(l.body)u.body=l.body;let p=new AbortController,m=setTimeout(()=>p.abort(),a);u.signal=p.signal;try{let g=await fetch(l.url,u);if(clearTimeout(m),g.ok)return g;if(c<n&&Br(g.status,s)){let f=bt(c,r,i);await St(f);continue}let y=await g.text();throw Error(`AWS API request failed (${g.status}): ${y}`)}catch(g){if(clearTimeout(m),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=bt(c,r,i);await St(y);continue}throw o}}throw o??Error("Request failed after retries")}async function vt(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 Tg(e){return await e.json()}function Rg(){Ge.clear()}function Pg(){return Ge.size}function Eg(){return Fe!==void 0}function wg(){return typeof crypto<"u"&&typeof crypto.subtle<"u"}var Fe,Ge,Ir=100,Xa;var _e=Ps(async()=>{try{Fe=await import("node:crypto")}catch{}Ge=new Map,Xa={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 Wl={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}},Vl={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 Lt,join as dt,relative as Is}from"node:path";var Ot=".ts-cloud",Un="TS_CLOUD_STATE_DIR",$t=null;function jl(e){$t=e?.trim()||null}function Kl(){return Boolean(process.env[Un]?.trim()||$t)}function Oe(){return process.env[Un]?.trim()||$t||Ot}function Hn(...e){return dt(Oe(),...e)}function Ds(e,...t){let n=Oe();return Lt(n)?dt(n,...t):dt(e,n,...t)}function ql(e,t=process.cwd()){let n=(i,s)=>{let a=Is(i,s);return a===""||!a.startsWith("..")&&!Lt(a)},r=Lt(e)?e:dt(t,e);return n(Ds(t),r)}function jn(e){let t=e.infrastructure?.compute!=null,n=Object.values(e.environments??{}).some((r)=>r?.app!=null);return{server:t,serverless:n}}function Ql(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:t}=jn(e);return t?"serverless":"server"}function Jl(e){let{server:t,serverless:n}=jn(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 Zl(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function Ns(e){return typeof e==="object"&&e!==null?e:{}}function xs(e){return e===!0||typeof e==="object"&&e!==null}function ks(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 Ms(e){let t=e.indexOf(".");return t>0?e.slice(t+1):void 0}function eu(e,t={}){let n=e.infrastructure?.compute?.managedServices?.mail,r=Ns(n),i=t.environmentType??(t.environment?e.environments?.[t.environment]?.type:void 0),s=r.mode??(i==="production"?"server":"catcher"),a=s==="server",o=ks(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},p=r.tls??{},m=p.enabled??a,g=!!(p.certPath&&p.keyPath),y=(r.accounts??[]).map((w)=>({address:w.address,password:w.password})),f=typeof r.dkim==="object"&&r.dkim!==null?r.dkim:{},S=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=r.spam??{},P=r.delivery??(a?"direct":"none"),R=r.expose??a,E=Ms(c),D=[...new Set([c,...E?[E]:[],...r.domains??[]])];return{enabled:xs(n),mode:s,version:r.version,hostname:c,domains:D,ports:u,tls:{enabled:m,acme:m&&!g&&(p.acme??!0),certPath:p.certPath,keyPath:p.keyPath,requireForAuth:p.requireForAuth??(m&&a),acmeEmail:p.acmeEmail??y[0]?.address},dkim:{enabled:S,selector:f.selector??"default",rotate:f.rotate??!1,rotateIntervalDays:f.rotateIntervalDays??90},webmail:{enabled:T,port:v.port??u.webmail,domain:v.domain},delivery:P,sesRegion:r.sesRegion??"us-east-1",accounts:y,storagePath:r.storagePath??"/var/lib/mail",maxMessageSize:r.maxMessageSize??26214400,spam:{enabled:A.enabled??a,enforce:A.enforce??!1,junkScore:A.junkScore??5,rejectScore:A.rejectScore??12,dnsbl:A.dnsbl??a,greylist:A.greylist??!1},webhookUrl:r.webhookUrl,expose:R,bindAddress:R?"0.0.0.0":"127.0.0.1"}}function tu(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 nu(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 iu(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 Ls{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}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 Ur(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 Hr(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 Hr(e){return Array.from(e).map((t)=>t.toString(16).padStart(2,"0")).join("")}function jr(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>=Fr){let m=s.keys().next().value;if(m)s.delete(m)}s.set(a,o)}return rt(o,i).toString("hex")}async function Kr(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>=Fr){let p=s.keys().next().value;if(p)s.delete(p)}s.set(a,o)}let c=await it(o,i);return Hr(c)}function qr(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&&qr(y.status,s)){let b=Tt(l,r,i);await Rt(b);continue}let f=await y.text();throw Error(`AWS API request failed (${y.status}): ${f}`)}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 f=Tt(l,r,i);await Rt(f);continue}throw o}}throw o??Error("Request failed after retries")}async function jg(e){return De(e,{maxRetries:0})}async function Kg(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 _r(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&&qr(g.status,s)){let f=Tt(c,r,i);await Rt(f);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 qg(e){return await e.json()}function zg(){We.clear()}function Qg(){return We.size}function Jg(){return _e!==void 0}function Yg(){return typeof crypto<"u"&&typeof crypto.subtle<"u"}var _e,We,Fr=100,yo;var Ve=Os(async()=>{try{_e=await import("node:crypto")}catch{}We=new Map,yo={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 nu={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}},ru={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 Fs}from"node:path";var _t=".ts-cloud",Qn="TS_CLOUD_STATE_DIR",Wt=null;function au(e){Wt=e?.trim()||null}function ou(){return Boolean(process.env[Qn]?.trim()||Wt)}function $e(){return process.env[Qn]?.trim()||Wt||_t}function Jn(...e){return gt($e(),...e)}function Gs(e,...t){let n=$e();return Gt(n)?gt(n,...t):gt(e,n,...t)}function cu(e,t=process.cwd()){let n=(i,s)=>{let a=Fs(i,s);return a===""||!a.startsWith("..")&&!Gt(a)},r=Gt(e)?e:gt(t,e);return n(Gs(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 uu(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:t}=Yn(e);return t?"serverless":"server"}function du(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 pu(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function _s(e){return typeof e==="object"&&e!==null?e:{}}function Ws(e){return e===!0||typeof e==="object"&&e!==null}function Vs(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 Us(e){let t=e.indexOf(".");return t>0?e.slice(t+1):void 0}function yu(e,t={}){let n=e.infrastructure?.compute?.managedServices?.mail,r=_s(n),i=t.environmentType??(t.environment?e.environments?.[t.environment]?.type:void 0),s=r.mode??(i==="production"?"server":"catcher"),a=s==="server",o=Vs(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((w)=>({address:w.address,password:w.password})),f=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=r.spam??{},P=r.delivery??(a?"direct":"none"),R=r.expose??a,E=Us(c),D=[...new Set([c,...E?[E]:[],...r.domains??[]])];return{enabled:Ws(n),mode:s,version:r.version,hostname:c,domains:D,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:f.selector??"default",rotate:f.rotate??!1,rotateIntervalDays:f.rotateIntervalDays??90},webmail:{enabled:T,port:v.port??u.webmail,domain:v.domain},delivery:P,sesRegion:r.sesRegion??"us-east-1",accounts:y,storagePath:r.storagePath??"/var/lib/mail",maxMessageSize:r.maxMessageSize??26214400,spam:{enabled:A.enabled??a,enforce:A.enforce??!1,junkScore:A.junkScore??5,rejectScore:A.rejectScore??12,dnsbl:A.dnsbl??a,greylist:A.greylist??!1},webhookUrl:r.webhookUrl,expose:R,bindAddress:R?"0.0.0.0":"127.0.0.1"}}function hu(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 fu(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 Su(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 Hs{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 Os(e){let t=[],n=[],r=[];if($s(e,t),e.Resources)Bs(e.Resources,t,n);else t.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});if(e.Parameters)Fs(e.Parameters,t,n);if(e.Outputs)Gs(e.Outputs,t);_s(e,t);let i=Ws(e);if(i.length>0)for(let s of i)t.push({path:"Resources",message:`Circular dependency detected: ${s.join(" → ")}`,severity:"error"});return Us(e,n,r),{valid:t.length===0,errors:t,warnings:n,info:r}}function $s(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 Bs(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&&Kn(s.Type))n.push({path:`Resources.${i}.DeletionPolicy`,message:`${s.Type} should specify DeletionPolicy to prevent accidental data loss`,severity:"warning"})}}function Fs(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 Gs(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 _s(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 Ws(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((p)=>c.add(p));else c.add(l.DependsOn);Vs(l).forEach((p)=>c.add(p)),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 p=c.indexOf(u),m=[...c.slice(p),u];r.push(m)}s.delete(o)}for(let o of n.keys())if(!i.has(o))a(o,[]);return r}function Vs(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 Kn(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 Us(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&&Hs(s.Type))n.push({path:`Resources.${i}`,message:`Consider adding Tags to ${s.Type}`,severity:"info"});if(Kn(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 Hs(e){return!["AWS::CloudFormation::Stack","AWS::CloudFormation::WaitCondition","AWS::CloudFormation::WaitConditionHandle"].includes(e)}function js(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 Ks(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})},qs={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 b(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 h(e){return e.split("-").map((t)=>t.charAt(0).toUpperCase()+t.slice(1)).join("")}function du(){return Date.now().toString()}function mu(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function gu(e,t){return e.project.stackName??`${e.project.slug}-${t}`}function yu(e,t,n,r){return n.stackName??`${e.project.slug}-${r}-${t}-site`}function hu(e,t){return`${e.project.slug}-${t}`}function fu(e,t,n,r){if(r)return r;if(n==="main")return`${e}-${t}-site`;return`${e}-${t}-${n}`}function bu(e,t,n,r){return r??`${e}-${t}-${n}`}function Su(e,t){return`${e}-${t}-deploy`}function Au(e,t){return`${e.project.slug}-${t}-app`}function Cu(e,t){return`${e}-${t}-deployments`}function qn(e,t){return`${e}-${t}-assets`}class zs{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 Ru(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 p of l){let m=o[p],g=c[p];if(!m&&g)n.push({logicalId:p,action:"add",resourceType:g.Type});else if(m&&!g)r.push({logicalId:p,action:"remove",resourceType:m.Type});else if(m&&g)if(m.Type!==g.Type)s.push({logicalId:p,action:"replace",resourceType:g.Type,reason:`Type changed from ${m.Type} to ${g.Type}`});else{let y=zn(m.Properties||{},g.Properties||{});if(y.length>0)if(Qs(m.Type,y))s.push({logicalId:p,action:"replace",resourceType:g.Type,changes:y,reason:"Property changes require replacement"});else i.push({logicalId:p,action:"update",resourceType:g.Type,changes:y});else a.push(p)}}let u=Js([...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 zn(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=zn(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 Qs(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 Js(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 Pu(e){let t=[];if(t.push(`=== Stack Update Analysis ===
|
|
18
|
+
`}return r}}function js(e){let t=[],n=[],r=[];if(Ks(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)zs(e.Parameters,t,n);if(e.Outputs)Qs(e.Outputs,t);Js(e,t);let i=Ys(e);if(i.length>0)for(let s of i)t.push({path:"Resources",message:`Circular dependency detected: ${s.join(" → ")}`,severity:"error"});return Xs(e,n,r),{valid:t.length===0,errors:t,warnings:n,info:r}}function Ks(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 zs(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 Qs(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 Js(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 Ys(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);Zs(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 Zs(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 Xs(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&&ea(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 ea(e){return!["AWS::CloudFormation::Stack","AWS::CloudFormation::WaitCondition","AWS::CloudFormation::WaitConditionHandle"].includes(e)}function ta(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 na(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})},ra={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 h(e){return e.split("-").map((t)=>t.charAt(0).toUpperCase()+t.slice(1)).join("")}function Eu(){return Date.now().toString()}function wu(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function Du(e,t){return e.project.stackName??`${e.project.slug}-${t}`}function Nu(e,t,n,r){return n.stackName??`${e.project.slug}-${r}-${t}-site`}function xu(e,t){return`${e.project.slug}-${t}`}function ku(e,t,n,r){if(r)return r;if(n==="main")return`${e}-${t}-site`;return`${e}-${t}-${n}`}function Mu(e,t,n,r){return r??`${e}-${t}-${n}`}function Lu(e,t){return`${e}-${t}-deploy`}function Ou(e,t){return`${e.project.slug}-${t}-app`}function $u(e,t){return`${e}-${t}-deployments`}function Xn(e,t){return`${e}-${t}-assets`}class ia{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 Gu(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(sa(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=aa([...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 sa(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 aa(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 _u(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 Qe,readdirSync as Ys}from"node:fs";import{join as Se}from"node:path";class we{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:p}=e,m=n??b({slug:r,environment:i,resourceType:"s3",suffix:t}),g=h(m),y={Type:"AWS::S3::Bucket",Properties:{BucketName:m}};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((S)=>({AllowedOrigins:S.allowedOrigins,AllowedMethods:S.allowedMethods,AllowedHeaders:S.allowedHeaders,MaxAge:S.maxAge}))};if(p&&p.length>0)y.Properties.LifecycleConfiguration={Rules:p.map((S)=>({Id:S.id,Status:S.enabled?"Enabled":"Disabled",ExpirationInDays:S.expirationDays,Transitions:S.transitions?.map((v)=>({TransitionInDays:v.days,StorageClass:v.storageClass}))}))};if(l&&p){let S={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!y.Properties.LifecycleConfiguration)y.Properties.LifecycleConfiguration={Rules:[]};y.Properties.LifecycleConfiguration.Rules.push({Id:S.id,Status:"Enabled",Transitions:S.transitions?.map((v)=>({TransitionInDays:v.days,StorageClass:v.storageClass}))})}let f;if(s)f={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:f,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||b({slug:n,environment:r,resourceType:"backup-vault",suffix:t}),p=h(u),m={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:u}},g=b({slug:n,environment:r,resourceType:"backup-role",suffix:t}),y=h(g),f={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"]}},S=b({slug:n,environment:r,resourceType:"backup-plan",suffix:t}),v=h(S),T={DeleteAfterDays:s};if(l&&l<s)T.MoveToColdStorageAfterDays=l;let A={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:S,BackupPlanRule:[{RuleName:`${t}-daily-backup`,TargetBackupVault:C.Ref(p),ScheduleExpression:a,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:T,EnableContinuousBackup:c}]}}},P=b({slug:n,environment:r,resourceType:"backup-selection",suffix:t}),R=h(P),E=i.map((w)=>C.GetAtt(w,"Arn")),D={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:C.Ref(v),BackupSelection:{SelectionName:P,IamRoleArn:C.GetAtt(y,"Arn"),Resources:E}}};return{vault:m,plan:A,selection:D,role:f,vaultLogicalId:p,planLogicalId:v,selectionLogicalId:R,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=b({slug:t,environment:n,resourceType:"s3",suffix:"www-redirect"}),o=h(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||b({slug:t,environment:n,resourceType:"s3",suffix:"docs"}),s=h(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=b({slug:t,environment:n,resourceType:"s3",suffix:"email"}),i=h(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=Se(t,r);if(Qe(i)){let s=["dist","build",".bunpress/dist","_site","out","public"];for(let a of s){let o=Se(i,a);if(Qe(o))try{if(Ys(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=we.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!t.exists)return{bucket:null,logicalId:null,docsInfo:t};let n=we.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=b({slug:t,environment:n,resourceType:"s3",suffix:"private"}),o=h(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:Qe(Se(t,r)),path:Se(t,r)},docs:{exists:Qe(Se(t,i)),path:Se(t,i)},private:{exists:Qe(Se(t,s)),path:Se(t,s)}}}static createDeploymentBuckets(e){let{slug:t,environment:n,domain:r,projectRoot:i,paths:s}=e,a=we.checkSourcePaths({projectRoot:i,paths:s}),o={},c={web:!1,docs:!1,private:!1},l=we.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=we.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=we.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=b({slug:n,environment:r,resourceType:"ecr",suffix:t}),p=h(u),m={Type:"AWS::ECR::Repository",Properties:{RepositoryName:u,ImageTagMutability:s,ImageScanningConfiguration:{ScanOnPush:i},EncryptionConfiguration:{EncryptionType:a,...o&&a==="KMS"?{KmsKey:o}:{}}}};if(c)m.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(pe.generateLifecyclePolicy(c))};if(l)m.Properties.Tags=Object.entries(l).map(([g,y])=>({Key:g,Value:y}));return{repository:m,logicalId:p}}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],p=l||`bun run ${n}`,m=`# Multi-stage build for Bun application
|
|
23
|
+
`)}import{existsSync as Ye,readdirSync as oa}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=h(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 f;if(s)f={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:f,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=h(u),p={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:u}},g=S({slug:n,environment:r,resourceType:"backup-role",suffix:t}),y=h(g),f={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=h(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}]}}},P=S({slug:n,environment:r,resourceType:"backup-selection",suffix:t}),R=h(P),E=i.map((w)=>C.GetAtt(w,"Arn")),D={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:C.Ref(v),BackupSelection:{SelectionName:P,IamRoleArn:C.GetAtt(y,"Arn"),Resources:E}}};return{vault:p,plan:A,selection:D,role:f,vaultLogicalId:m,planLogicalId:v,selectionLogicalId:R,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=h(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=h(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=h(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(oa(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=h(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=h(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
|
|
24
24
|
# Generated by ts-cloud
|
|
25
25
|
|
|
26
26
|
# Builder stage
|
|
@@ -47,18 +47,18 @@ COPY --from=builder /app/node_modules ./node_modules
|
|
|
47
47
|
|
|
48
48
|
# Copy application code
|
|
49
49
|
COPY package.json ./
|
|
50
|
-
`;for(let g of u)
|
|
51
|
-
`;if(
|
|
52
|
-
`,c.length>0){
|
|
50
|
+
`;for(let g of u)p+=`COPY ${g} ./${g}
|
|
51
|
+
`;if(p+=`COPY ${n} ./${n}
|
|
52
|
+
`,c.length>0){p+=`
|
|
53
53
|
# Build commands
|
|
54
|
-
`;for(let g of c)
|
|
55
|
-
`}
|
|
54
|
+
`;for(let g of c)p+=`RUN ${g}
|
|
55
|
+
`}p+=`
|
|
56
56
|
# Environment variables
|
|
57
|
-
`,
|
|
58
|
-
`,
|
|
59
|
-
`;for(let[g,y]of Object.entries(o))
|
|
60
|
-
`;if(a)
|
|
61
|
-
`;return
|
|
57
|
+
`,p+=`ENV NODE_ENV=production
|
|
58
|
+
`,p+=`ENV PORT=${r}
|
|
59
|
+
`;for(let[g,y]of Object.entries(o))p+=`ENV ${g}=${y}
|
|
60
|
+
`;if(a)p+=`ENV BUN_INSTALL_FORCE_NODE_API=1
|
|
61
|
+
`;return p+=`
|
|
62
62
|
# Create storage directory
|
|
63
63
|
RUN mkdir -p /app/storage && chown -R app:app /app/storage
|
|
64
64
|
|
|
@@ -74,7 +74,7 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\
|
|
|
74
74
|
|
|
75
75
|
# Start application
|
|
76
76
|
CMD ["bun", "run", "${n}"]
|
|
77
|
-
`,
|
|
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,f]of Object.entries(a))m+=` --build-arg ${y}=${f}`;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
|
|
78
78
|
set -e
|
|
79
79
|
|
|
80
80
|
# Configuration
|
|
@@ -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 Bt=[400,403,404,416,429,500,502,503,504],Qn=[500,502,503,504],Jn=["GET","HEAD","OPTIONS"],Lu="-failover-group";function Zs(e){if(e===void 0)return[...Qn];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${Bt.join(", ")}). Omit it to use the default ${Qn.join(", ")}.`);let t=e.filter((n)=>!Bt.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: ${Bt.join(", ")}.`);return[...new Set(e)].sort((n,r)=>n-r)}function Ft(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=Zs(e.statusCodes);return{Id:e.groupId??`${t}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:r.length,Items:r}},Members:{Quantity:2,Items:[{OriginId:t},{OriginId:n}]}}}function Ou(e){return{Quantity:1,Items:[Ft(e)]}}function Yn(e,t="the cache behavior"){let r=(Array.isArray(e)?e:e?.Items??[]).filter((i)=>!Jn.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 ${Jn.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function Zn(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}class re{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:p}=e,m=b({slug:t,environment:n,resourceType:"cdn"}),g=h(m),y={Id:"DefaultOrigin",DomainName:r.domainName,OriginPath:r.originPath||""},f;if(r.type==="s3"){let v=`${g}OAC`;f={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${m}-oac`,Description:`Origin Access Control for ${m}`,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 S={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:u||`CDN for ${m}`,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)S.Properties.DistributionConfig.Aliases=[i],S.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(a&&a.length>0)S.Properties.DistributionConfig.CustomErrorResponses=a.map((v)=>({ErrorCode:v.errorCode,ResponseCode:v.responseCode,ResponsePagePath:v.responsePagePath}));if(c&&c.length>0)S.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=c.map((v)=>({EventType:v.event,LambdaFunctionARN:v.functionArn}));if(p)re.addOriginFailover(S,p);return{distribution:S,originAccessControl:f,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(Yn(r.AllowedMethods??["GET","HEAD"],"the default cache behavior"),n.Origins.some((l)=>l.Id===s))throw Error(`CloudFront origin failover: an origin with id "${s}" already exists`);let a=Ft({primaryOriginId:i,secondaryOriginId:s,statusCodes:t.statusCodes}),o=t.type??(Zn(t.domainName)?"s3":"custom"),c={Id:s,DomainName:t.domainName,OriginPath:t.originPath||""};if(o==="s3"){let l=n.Origins.find((u)=>u.Id===i);if(c.S3OriginConfig={OriginAccessIdentity:""},l?.OriginAccessControlId)c.OriginAccessControlId=l.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,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 re.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=b({slug:t,environment:n,resourceType:"edge-docs"}),i=h(r),s=h(`${r}-role`),a=h(`${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)=>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"],Qu="-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 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 Ju(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 ca=/\.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 f=y.map((T)=>ge(T.OriginId));for(let T of f)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(f[0]&&f[0]===f[1])throw Error(`CloudFront origin failover: ${p} lists "${f[0]}" as both primary and secondary.`);let b=u.FailoverCriteria?.StatusCodes,v=Ze(b);if(ht(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 f){let A=T?ge(i.get(T)):void 0;if(A&&!ca.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 re{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=h(p),y={Id:"DefaultOrigin",DomainName:r.domainName,OriginPath:r.originPath||"",...Be(r,"the CDN origin")},f;if(r.type==="s3"){let v=`${g}OAC`;f={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)re.addOriginFailover(b,m);return{distribution:b,originAccessControl:f,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 re.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=h(r),s=h(`${r}-role`),a=h(`${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=re.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)re.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,
|
|
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=re.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)re.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=h(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 f={Forward:c};if(c==="whitelist"&&l)f.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:f}},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=h(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)},f={Id:"ALBOrigin",DomainName:i,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(g.length>0)f.OriginCustomHeaders=g;let b={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`Multi-origin CDN for ${l}`,DefaultRootObject:"index.html",Origins:[y,f],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:re.Config.allowedMethods(i),CachedMethods:re.Config.cachedMethods(s),ForwardedValues:{QueryString:o,Headers:c,Cookies:re.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=re.Config.allowedMethods(t.allowedMethods);if(t.cachedMethods)n.CachedMethods=re.Config.cachedMethods(t.cachedMethods);if(t.cookies){if(!n.ForwardedValues)n.ForwardedValues={QueryString:!0};n.ForwardedValues.Cookies=re.Config.cookies(t.cookies,t.allowedCookies)}return e}}class z{static createHostedZone(e){let{domain:t,slug:n,environment:r,comment:i}=e,s=b({slug:n,environment:r,resourceType:"hostedzone"}),a=h(`${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=h(`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 z.createRecord({hostedZoneId:n,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,t,n,r){return z.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:n,evaluateTargetHealth:!0}})}static createCname(e,t,n,r=300){return z.createRecord({hostedZoneId:n,name:e,type:"CNAME",ttl:r,values:[t]})}static createWwwRedirect(e,t){return z.createRecord({hostedZoneId:t,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,t,n,r=300){return z.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 z.createRecord({hostedZoneId:n,name:e,type:"TXT",ttl:r,values:[`"${t}"`]})}static createSpfRecord(e,t,n){return z.createTxtRecord(e,t,n)}static createDmarcRecord(e,t,n,r){let i=`v=DMARC1; p=${t}; rua=mailto:${n}`;return z.createTxtRecord(`_dmarc.${e}`,i,r)}static createS3WebsiteAlias(e,t,n,r){return z.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 z.createCname(`store.${e}`,t,n)}static createApiRecord(e,t,n){return z.createCname(`api.${e}`,t,n)}static createDocsRecord(e,t,n){return z.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=b({slug:r,environment:i,resourceType:"acm"}),c=h(`${o}-${t.replace(/\./g,"")}`),l=[t];for(let p of n)if(p==="*")l.push(`*.${t}`);else l.push(`${p}.${t}`);let u={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:t,SubjectAlternativeNames:l,ValidationMethod:s}};if(s==="DNS"&&a)u.Properties.DomainValidationOptions=l.map((p)=>({DomainName:p,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=b({slug:n,environment:r,resourceType:"kms"}),o=h(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=h(`${a}-alias`),p={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${n}-${r}`,TargetKeyId:C.Ref(o)}};return{key:l,alias:p,logicalId:o,aliasId:u}}static createFirewall(e){let{slug:t,environment:n,scope:r="CLOUDFRONT",defaultAction:i="allow"}=e,s=b({slug:t,environment:n,resourceType:"waf"}),a=h(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=b({slug:n,environment:r,resourceType:"ipset"}),s=h(`${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}}class x{static createServer(e){let{slug:t,environment:n,instanceType:r="t3.micro",imageId:i="ami-0f3caa1cf4417e51b",keyName:s,securityGroupIds:a,subnetId:o,userData:c,volumeSize:l=20,volumeType:u="gp3",encrypted:p=!0}=e,m=b({slug:t,environment:n,resourceType:"ec2"}),g=h(m),y={Type:"AWS::EC2::Instance",Properties:{ImageId:i,InstanceType:r,Tags:[{Key:"Name",Value:m},{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:p,DeleteOnTermination:!0}}],{instance:y,logicalId:g}}static createSecurityGroup(e){let{slug:t,environment:n,vpcId:r,description:i,ingress:s=[],egress:a=[]}=e,o=b({slug:t,environment:n,resourceType:"sg"}),c=h(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=b({slug:t,environment:n,resourceType:"alb"}),c=h(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:p=3}=e,m=b({slug:t,environment:n,resourceType:"tg"}),g=h(m);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:m,Port:r,Protocol:i,VpcId:s,TargetType:a,HealthCheckEnabled:!0,HealthCheckProtocol:i,HealthCheckPath:o,HealthCheckIntervalSeconds:c,HealthCheckTimeoutSeconds:l,HealthyThresholdCount:u,UnhealthyThresholdCount:p,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:n}]}},logicalId:g}}static createListener(e,t){let{port:n,protocol:r="HTTP",certificateArn:i,defaultTargetGroupArn:s}=t,a=h(`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=b({slug:e,environment:t,resourceType:"ecs-cluster"}),r=h(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:p,subnets:m,securityGroups:g,targetGroupArn:y}=e,{cluster:f,logicalId:S}=x.createEcsCluster(t,n),v=b({slug:t,environment:n,resourceType:"fargate"}),T=h(`${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"]}},P=h(`${v}-task-role`),R={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},E=h(`${v}-task`),D={Type:"AWS::ECS::TaskDefinition",Properties:{Family:v,TaskRoleArn:C.GetAtt(P,"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)D.Properties.ContainerDefinitions[0].HealthCheck={Command:u.command,Interval:u.interval||30,Timeout:u.timeout||5,Retries:u.retries||3,StartPeriod:60};if(p)D.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":p,"awslogs-region":C.Ref("AWS::Region"),"awslogs-stream-prefix":t}};let w=h(`${v}-service`),N={Type:"AWS::ECS::Service",Properties:{ServiceName:v,Cluster:C.Ref(S),TaskDefinition:C.Ref(E),DesiredCount:a,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:m,SecurityGroups:g,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:v},{Key:"Environment",Value:n}]}};if(y)N.Properties.LoadBalancers=[{TargetGroupArn:y,ContainerName:t,ContainerPort:o}];return{cluster:f,taskDefinition:D,service:N,taskRole:R,executionRole:A,clusterLogicalId:S,taskDefinitionLogicalId:E,serviceLogicalId:w,taskRoleLogicalId:P,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=b({slug:t,environment:n,resourceType:"lambda"}),p=h(u),m=h(`${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(m,"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:p,roleLogicalId:m}}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:re.Config.allowedMethods(i),CachedMethods:re.Config.cachedMethods(s),ForwardedValues:{QueryString:o,Headers:c,Cookies:re.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=re.Config.allowedMethods(t.allowedMethods);if(t.cachedMethods)n.CachedMethods=re.Config.cachedMethods(t.cachedMethods);if(t.cookies){if(!n.ForwardedValues)n.ForwardedValues={QueryString:!0};n.ForwardedValues.Cookies=re.Config.cookies(t.cookies,t.allowedCookies)}return e}}var la=[403,404,500,502,503,504],ua="TsCloud::StorageFailover",da="AllowCloudFrontFailoverRead",ma=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,pa=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function rd(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||!ma.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(!pa.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??la),primaryConnection:Be(t,`${i}.failover`)}}function id(e,t){return`${e}.s3.${t}.amazonaws.com`}function sd(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 ad(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 od(e){return{Sid:da,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function cd(e){let n=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[ua];return Array.isArray(n)?n:[]}class z{static createHostedZone(e){let{domain:t,slug:n,environment:r,comment:i}=e,s=S({slug:n,environment:r,resourceType:"hostedzone"}),a=h(`${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=h(`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 z.createRecord({hostedZoneId:n,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,t,n,r){return z.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:n,evaluateTargetHealth:!0}})}static createCname(e,t,n,r=300){return z.createRecord({hostedZoneId:n,name:e,type:"CNAME",ttl:r,values:[t]})}static createWwwRedirect(e,t){return z.createRecord({hostedZoneId:t,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,t,n,r=300){return z.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 z.createRecord({hostedZoneId:n,name:e,type:"TXT",ttl:r,values:[`"${t}"`]})}static createSpfRecord(e,t,n){return z.createTxtRecord(e,t,n)}static createDmarcRecord(e,t,n,r){let i=`v=DMARC1; p=${t}; rua=mailto:${n}`;return z.createTxtRecord(`_dmarc.${e}`,i,r)}static createS3WebsiteAlias(e,t,n,r){return z.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 z.createCname(`store.${e}`,t,n)}static createApiRecord(e,t,n){return z.createCname(`api.${e}`,t,n)}static createDocsRecord(e,t,n){return z.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=h(`${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=h(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=h(`${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=h(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=h(`${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}}class x{static createServer(e){let{slug:t,environment:n,instanceType:r="t3.micro",imageId:i="ami-0f3caa1cf4417e51b",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=h(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=h(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=h(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=h(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=h(`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=h(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:f,logicalId:b}=x.createEcsCluster(t,n),v=S({slug:t,environment:n,resourceType:"fargate"}),T=h(`${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"]}},P=h(`${v}-task-role`),R={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},E=h(`${v}-task`),D={Type:"AWS::ECS::TaskDefinition",Properties:{Family:v,TaskRoleArn:C.GetAtt(P,"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)D.Properties.ContainerDefinitions[0].HealthCheck={Command:u.command,Interval:u.interval||30,Timeout:u.timeout||5,Retries:u.retries||3,StartPeriod:60};if(m)D.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":m,"awslogs-region":C.Ref("AWS::Region"),"awslogs-stream-prefix":t}};let w=h(`${v}-service`),N={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)N.Properties.LoadBalancers=[{TargetGroupArn:y,ContainerName:t,ContainerPort:o}];return{cluster:f,taskDefinition:D,service:N,taskRole:R,executionRole:A,clusterLogicalId:b,taskDefinitionLogicalId:E,serviceLogicalId:w,taskRoleLogicalId:P,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=h(u),p=h(`${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(`
|
|
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:
|
|
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=h(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=h(g),f={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)f.Properties.DesiredCapacity=a;if(o)f.Properties.VPCZoneIdentifier=o;if(c)f.Properties.TargetGroupARNs=c;return f.UpdatePolicy={AutoScalingRollingUpdate:{MaxBatchSize:1,MinInstancesInService:Math.max(0,i-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:f,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=h(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="ami-0f3caa1cf4417e51b",allowedCidrs:c=["0.0.0.0/0"],mountEfs:l}=e,u=S({slug:t,environment:n,resourceType:"jumpbox"}),m=h(`${u}-sg`),p={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:`${u}-sg`,GroupDescription:`Security group for ${u} JumpBox SSH access`,VpcId:r,SecurityGroupIngress:c.map((R)=>({IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:R,Description:`SSH access from ${R}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound traffic"}],Tags:[{Key:"Name",Value:`${u}-sg`},{Key:"Environment",Value:n}]}},g=h(`${u}-role`),y={Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-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:l?[{PolicyName:"EFSAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess"],Resource:"*"}]}}]:void 0}},f=h(`${u}-profile`),b={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:`${u}-profile`,Roles:[C.Ref(g)]}},v=`#!/bin/bash
|
|
314
314
|
yum update -y
|
|
315
315
|
yum install -y amazon-efs-utils nfs-utils jq curl wget htop
|
|
316
316
|
`;if(l){let R=l.mountPath||"/mnt/efs";v+=`
|
|
@@ -318,7 +318,7 @@ yum install -y amazon-efs-utils nfs-utils jq curl wget htop
|
|
|
318
318
|
mkdir -p ${R}
|
|
319
319
|
mount -t efs ${l.fileSystemId}:/ ${R}
|
|
320
320
|
echo "${l.fileSystemId}:/ ${R} efs defaults,_netdev 0 0" >> /etc/fstab
|
|
321
|
-
`}let T=h(u),A={Type:"AWS::EC2::Instance",DependsOn:[f],Properties:{ImageId:o,InstanceType:a,KeyName:s,SubnetId:i,SecurityGroupIds:[C.Ref(
|
|
321
|
+
`}let T=h(u),A={Type:"AWS::EC2::Instance",DependsOn:[f],Properties:{ImageId:o,InstanceType:a,KeyName:s,SubnetId:i,SecurityGroupIds:[C.Ref(m)],IamInstanceProfile:C.Ref(f),UserData:C.Base64(v),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n},{Key:"Purpose",Value:"JumpBox/Bastion"}]}},P={[m]:p,[g]:y,[f]:b,[T]:A};return{instance:A,securityGroup:p,instanceProfile:b,instanceRole:y,instanceLogicalId:T,securityGroupLogicalId:m,instanceProfileLogicalId:f,instanceRoleLogicalId:g,resources:P}}static JumpBox={withEfsMount:(e)=>x.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,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)=>{let t=x.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,allowedCidrs:e.allowedCidrs}),n=`#!/bin/bash
|
|
322
322
|
yum update -y
|
|
323
323
|
yum install -y amazon-efs-utils nfs-utils jq curl wget htop
|
|
324
324
|
|
|
@@ -346,7 +346,7 @@ yum install -y mysql
|
|
|
346
346
|
yum install -y redis
|
|
347
347
|
|
|
348
348
|
echo "Database tools installed!"
|
|
349
|
-
`),t},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:
|
|
349
|
+
`),t},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
|
|
350
350
|
set -e
|
|
351
351
|
|
|
352
352
|
# Update system
|
|
@@ -356,7 +356,7 @@ apt-get update && apt-get upgrade -y
|
|
|
356
356
|
# Install basic tools
|
|
357
357
|
apt-get install -y curl wget git jq htop unzip
|
|
358
358
|
|
|
359
|
-
`;if(t==="bun")
|
|
359
|
+
`;if(t==="bun")p+=x.UserData.Scripts.bun(n);else p+=x.UserData.Scripts.nodeJs(n);if(r==="nginx"){if(p+=x.UserData.Scripts.nginx(),o&&s)p+=x.UserData.Scripts.nginxProxy(o,c)}else if(r==="caddy"){if(p+=x.UserData.Scripts.caddy(),o)p+=x.UserData.Scripts.caddyProxy(o,c)}if(i==="pm2"&&t==="node")p+=x.UserData.Scripts.pm2();if(s&&r==="nginx"&&o)p+=x.UserData.Scripts.letsEncrypt(o,a);if(l)p+=x.UserData.Scripts.databaseClients();if(u)p+=x.UserData.Scripts.redis();if(p+=`
|
|
360
360
|
# Install AWS CLI
|
|
361
361
|
if ! command -v aws &> /dev/null; then
|
|
362
362
|
curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m).zip" -o /tmp/awscliv2.zip
|
|
@@ -364,10 +364,10 @@ if ! command -v aws &> /dev/null; then
|
|
|
364
364
|
/tmp/aws/install
|
|
365
365
|
rm -rf /tmp/aws /tmp/awscliv2.zip
|
|
366
366
|
fi
|
|
367
|
-
`,
|
|
367
|
+
`,m.length>0)p+=`
|
|
368
368
|
# Install extra packages
|
|
369
|
-
apt-get install -y ${
|
|
370
|
-
`;return
|
|
369
|
+
apt-get install -y ${m.join(" ")}
|
|
370
|
+
`;return p+=`
|
|
371
371
|
# Create API server directory
|
|
372
372
|
mkdir -p /var/www/api
|
|
373
373
|
|
|
@@ -391,9 +391,9 @@ SERVICEFILE
|
|
|
391
391
|
|
|
392
392
|
systemctl daemon-reload
|
|
393
393
|
systemctl enable stacks-api
|
|
394
|
-
`,
|
|
394
|
+
`,p+=`
|
|
395
395
|
echo "Server setup complete!"
|
|
396
|
-
`,
|
|
396
|
+
`,p},generateBunAppScript:(e)=>{let{runtime:t="bun",runtimeVersion:n="latest",systemPackages:r=[],database:i,caddyfile:s}=e,a=new Set(r);if(i==="sqlite")a.add("sqlite");else if(i==="mysql")a.add("mysql");else if(i==="postgres")a.add("postgresql15");let o=`#!/bin/bash
|
|
397
397
|
set -euo pipefail
|
|
398
398
|
|
|
399
399
|
# Amazon Linux 2023 base setup
|
|
@@ -604,7 +604,7 @@ ufw default allow outgoing
|
|
|
604
604
|
${e.map((t)=>`ufw allow ${t}`).join(`
|
|
605
605
|
`)}
|
|
606
606
|
ufw --force enable
|
|
607
|
-
`},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=
|
|
607
|
+
`},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=h(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=h(`${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"}),f=h(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[f]=b;let v=S({slug:t,environment:n,resourceType:"server-role"}),T=h(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 P=S({slug:t,environment:n,resourceType:"server-profile"}),R=h(P),E={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:P,Roles:[C.Ref(T)]}};g[R]=E;let D=S({slug:t,environment:n,resourceType:"server"}),w=h(D),N={Type:"AWS::EC2::Instance",DependsOn:[R],Properties:{ImageId:a,InstanceType:s,KeyName:o,SubnetId:i,SecurityGroupIds:[C.Ref(f)],IamInstanceProfile:C.Ref(R),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:n},...c?[{Key:"Domain",Value:c}]:[]]}};if(l)N.Properties.UserData=C.Base64(l);g[w]=N;let{eip:k,eipAssociation:O,eipLogicalId:le,associationLogicalId:j,resources:ne}=x.createElasticIp({slug:t,environment:n,domain:c,instanceLogicalId:w});return Object.assign(g,ne),{instance:N,securityGroup:b,eip:k,eipAssociation:O,instanceRole:A,instanceProfile:E,resources:g,outputs:{instanceLogicalId:w,securityGroupLogicalId:f,eipLogicalId:le,associationLogicalId:j,roleLogicalId:T,profileLogicalId:R}}}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
|
|
608
608
|
set -e
|
|
609
609
|
apt-get update && apt-get upgrade -y
|
|
610
610
|
apt-get install -y redis-server
|
|
@@ -612,7 +612,7 @@ sed -i 's/bind 127.0.0.1/bind 0.0.0.0/' /etc/redis/redis.conf
|
|
|
612
612
|
systemctl enable redis-server
|
|
613
613
|
systemctl restart redis-server
|
|
614
614
|
echo "Redis server setup complete!"
|
|
615
|
-
`,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class B{static createVpc(e){let{slug:t,environment:n,cidr:r="10.0.0.0/16",enableDnsHostnames:i=!0,enableDnsSupport:s=!0}=e,a=
|
|
615
|
+
`,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=h(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=h(`${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=h(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=h(`${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=h(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=h(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=h(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=h(`${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=h(`${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=h(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 f=0;f<t*n;f++){let b=p+f*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:f,logicalId:b}=B.createInternetGateway(t,n);l[b]=f;let{attachment:v,logicalId:T}=B.attachInternetGateway(y,b);l[T]=v;let{routeTable:A,logicalId:P}=B.createRouteTable(t,n,y,"public");l[P]=A;let{route:R,logicalId:E}=B.createRoute(P,"0.0.0.0/0",{type:"igw",logicalId:b});R.DependsOn=T,l[E]=R;let D=B.calculateSubnetCidrs(i,s,2),w=B.getAvailabilityZones(r,s),N=[];for(let k=0;k<s;k++){let O=w[k],le=D[k*2],j=D[k*2+1],{subnet:ne,logicalId:U}=B.createSubnet({slug:t,environment:n,vpcId:C.Ref(y),type:"public",cidr:le,availabilityZone:O});l[U]=ne,u.push(U);let{association:Pe,logicalId:qe}=B.associateSubnetWithRouteTable(U,P);l[qe]=Pe;let{subnet:Bt,logicalId:ue}=B.createSubnet({slug:t,environment:n,vpcId:C.Ref(y),type:"private",cidr:j,availabilityZone:O});if(l[ue]=Bt,m.push(ue),a&&(!o||k===0)){let{eip:ie,logicalId:de}=B.createEip(`${t}-${O}`,n);l[de]=ie;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,N.push(Le);let{route:ze,logicalId:I}=B.createRoute(Le,"0.0.0.0/0",{type:"nat",logicalId:me});l[I]=ze;let{association:M,logicalId:F}=B.associateSubnetWithRouteTable(ue,Le);l[F]=M}else if(a&&o&&k>0){let{association:ie,logicalId:de}=B.associateSubnetWithRouteTable(ue,N[0]);l[de]=ie}else{let{routeTable:ie,logicalId:de}=B.createRouteTable(`${t}-${O}-isolated`,n,y,"private");l[de]=ie;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=`
|
|
616
616
|
⚠️ NAT Gateway Cost Warning:
|
|
617
617
|
- Each NAT Gateway costs approximately $32-45/month (hourly charges)
|
|
618
618
|
- Data processing charges: $0.045/GB processed
|
|
@@ -620,7 +620,7 @@ echo "Redis server setup complete!"
|
|
|
620
620
|
- Using a single NAT Gateway (singleNatGateway: true)
|
|
621
621
|
- Using NAT Instances instead (cheaper but requires management)
|
|
622
622
|
- Disabling NAT entirely for isolated private subnets
|
|
623
|
-
`}class Je{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=b({slug:t,environment:n,resourceType:"efs"}),u=h(l),p={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:r,PerformanceMode:s,ThroughputMode:a,FileSystemTags:[{Key:"Name",Value:l},{Key:"Environment",Value:n}]}};if(i)p.Properties.KmsKeyId=i;if(a==="provisioned"&&o)p.Properties.ProvisionedThroughputInMibps=o;if(c)p.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:p,logicalId:u}}static createMountTarget(e,t){let{slug:n,environment:r,subnetId:i,securityGroups:s,ipAddress:a}=t,o=b({slug:n,environment:r,resourceType:"efs-mt"}),c=h(`${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=b({slug:n,environment:r,resourceType:"efs-ap"}),l=h(`${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=b({slug:t,environment:n,resourceType:"efs-sg"}),c=h(o),l=[];for(let p of i)l.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:p,Description:"NFS from security group"});for(let p of s)l.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:p,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=b({slug:n,environment:r,resourceType:"efs-mt"}),p=h(`${u}-az${c+1}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:C.Ref(e),SubnetId:l,SecurityGroups:[s]}};a.push(m),o.push(p)}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,p={},{fileSystem:m,logicalId:g}=Je.createFileSystem({slug:t,environment:n,encrypted:a,performanceMode:o,throughputMode:c,enableBackup:l});if(u)Je.setLifecyclePolicy(m,{transitionToIA:u,transitionToPrimary:!0});p[g]=m;let{securityGroup:y,logicalId:f}=Je.createEfsSecurityGroup({slug:t,environment:n,vpcId:r,sourceSecurityGroupIds:s});p[f]=y;let{mountTargets:S,logicalIds:v}=Je.createMultiAzMountTargets(g,{slug:t,environment:n,subnetIds:i,securityGroupId:C.Ref(f)});for(let T=0;T<S.length;T++)p[v[T]]=S[T];return{resources:p,outputs:{fileSystemId:g,securityGroupId:f,mountTargetIds:v}}}}class G{static verifyDomain(e){let{domain:t,slug:n,environment:r,enableDkim:i=!0,dkimKeyLength:s="RSA_2048_BIT"}=e,a=b({slug:n,environment:r,resourceType:"ses-identity"}),o=h(`${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=h(`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||b({slug:t,environment:n,resourceType:"ses-config"}),l=h(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||b({slug:t,environment:n,resourceType:"ses-ruleset"}),s=h(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:p}=t,m=b({slug:n,environment:r,resourceType:"ses-rule"}),g=h(m),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(p)y.push({SNSAction:{TopicArn:p.topicArn,Encoding:p.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:i,Rule:{Name:m,Enabled:a,ScanEnabled:o,TlsPolicy:c,Recipients:s,Actions:y.length>0?y:void 0}}},logicalId:g}}static createMxRecord(e,t,n){let r=h(`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=h(`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=h(`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=h(`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:p,logicalId:m}=G.createReceiptRuleSet({slug:t,environment:n});u[m]=p;let{receiptRule:g,logicalId:y}=G.createReceiptRule(m,{slug:t,environment:n,ruleSetName:p.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:f,logicalId:S}=G.createMxRecord(r,o,a);return u[S]=f,{resources:u,outputs:{ruleSetLogicalId:m,ruleLogicalId:y,mxRecordLogicalId:S}}}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:p}=G.verifyDomain({domain:r,slug:t,environment:n});l[p]=u;let{configurationSet:m,logicalId:g}=G.createConfigurationSet({slug:t,environment:n});l[g]=m;let{record:y,logicalId:f}=G.createSpfRecord(r,i);l[f]=y;let{record:S,logicalId:v}=G.createDmarcRecord(r,i,{policy:"none",reportingEmail:c||`dmarc-reports@${r}`});if(l[v]=S,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:p,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=b({slug:t,environment:n,resourceType:"email-lambda-role"}),a=h(s),o=h(`${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=b({slug:t,environment:n,resourceType:"outbound-email"}),l=h(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=b({slug:t,environment:n,resourceType:"inbound-email"}),l=h(c),u=h(`${c}-permission`),p={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"}]}},m={Type:"AWS::Lambda::Permission",Properties:{FunctionName:C.Ref(l),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:C.Ref("AWS::AccountId")}};return{function:p,permission:m,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=b({slug:t,environment:n,resourceType:"email-conversion"}),l=h(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=b({slug:t,environment:n,resourceType:"s3-lambda-permission"}),a=h(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:p,roleLogicalId:m,policyLogicalId:g}=G.createEmailLambdaRole({slug:t,environment:n,s3BucketArn:s,sesIdentityArn:`arn:aws:ses:*:*:identity/${r}`});l[m]=u,l[g]=p;let{function:y,logicalId:f}=G.createOutboundEmailLambda({slug:t,environment:n,roleArn:C.GetAtt(m,"Arn"),domain:r,configurationSetName:a});l[f]=y;let S={roleLogicalId:m,outboundLambdaLogicalId:f};if(o){let{function:v,permission:T,logicalId:A,permissionLogicalId:P}=G.createInboundEmailLambda({slug:t,environment:n,roleArn:C.GetAtt(m,"Arn"),s3BucketName:i});l[A]=v,l[P]=T;let{permission:R,logicalId:E}=G.createS3LambdaPermission({slug:t,environment:n,lambdaLogicalId:A,s3BucketArn:s});l[E]=R,S.inboundLambdaLogicalId=A}if(c){let{function:v,logicalId:T}=G.createEmailConversionLambda({slug:t,environment:n,roleArn:C.GetAtt(m,"Arn"),s3BucketName:i});l[T]=v,S.conversionLambdaLogicalId=T}return{resources:l,outputs:S}}static LambdaCode={outboundEmail:`
|
|
623
|
+
`}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=h(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=h(`${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=h(`${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=h(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=h(`${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:f}=Xe.createEfsSecurityGroup({slug:t,environment:n,vpcId:r,sourceSecurityGroupIds:s});m[f]=y;let{mountTargets:b,logicalIds:v}=Xe.createMultiAzMountTargets(g,{slug:t,environment:n,subnetIds:i,securityGroupId:C.Ref(f)});for(let T=0;T<b.length;T++)m[v[T]]=b[T];return{resources:m,outputs:{fileSystemId:g,securityGroupId:f,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=h(`${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=h(`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=h(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=h(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=h(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=h(`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=h(`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=h(`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=h(`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:f,logicalId:b}=G.createMxRecord(r,o,a);return u[b]=f,{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:f}=G.createSpfRecord(r,i);l[f]=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=h(s),o=h(`${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=h(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=h(c),u=h(`${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=h(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=h(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:f}=G.createOutboundEmailLambda({slug:t,environment:n,roleArn:C.GetAtt(p,"Arn"),domain:r,configurationSetName:a});l[f]=y;let b={roleLogicalId:p,outboundLambdaLogicalId:f};if(o){let{function:v,permission:T,logicalId:A,permissionLogicalId:P}=G.createInboundEmailLambda({slug:t,environment:n,roleArn:C.GetAtt(p,"Arn"),s3BucketName:i});l[A]=v,l[P]=T;let{permission:R,logicalId:E}=G.createS3LambdaPermission({slug:t,environment:n,lambdaLogicalId:A,s3BucketArn:s});l[E]=R,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:`
|
|
624
624
|
const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
|
|
625
625
|
const ses = new SESClient({});
|
|
626
626
|
|
|
@@ -1166,7 +1166,7 @@ else if (encoding === 'quoted-printable') {
|
|
|
1166
1166
|
|
|
1167
1167
|
return content;
|
|
1168
1168
|
}
|
|
1169
|
-
`}}var
|
|
1169
|
+
`}}var lr={};Oe(lr,{default:()=>ga,handler:()=>jt});var jt=`
|
|
1170
1170
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1171
1171
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1172
1172
|
|
|
@@ -1273,7 +1273,7 @@ catch (error) {
|
|
|
1273
1273
|
};
|
|
1274
1274
|
}
|
|
1275
1275
|
};
|
|
1276
|
-
`,
|
|
1276
|
+
`,ga=`
|
|
1277
1277
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1278
1278
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1279
1279
|
|
|
@@ -1380,7 +1380,7 @@ catch (error) {
|
|
|
1380
1380
|
};
|
|
1381
1381
|
}
|
|
1382
1382
|
};
|
|
1383
|
-
`;var
|
|
1383
|
+
`;var ur=`
|
|
1384
1384
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1385
1385
|
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1386
1386
|
|
|
@@ -1487,7 +1487,7 @@ catch (error) {
|
|
|
1487
1487
|
};
|
|
1488
1488
|
}
|
|
1489
1489
|
};
|
|
1490
|
-
`;var
|
|
1490
|
+
`;var dr=`
|
|
1491
1491
|
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
1492
1492
|
const { TranscribeClient, StartTranscriptionJobCommand, GetTranscriptionJobCommand } = require('@aws-sdk/client-transcribe');
|
|
1493
1493
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
@@ -1658,7 +1658,7 @@ catch (error) {
|
|
|
1658
1658
|
|
|
1659
1659
|
return { statusCode: 200, body: 'OK' };
|
|
1660
1660
|
};
|
|
1661
|
-
`;class ge{static LambdaCode={incomingCall:Gt,voicemail:tr,missedCall:er};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:ge.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:ge.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:ge.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,ge.createPhoneLambdaRole({slug:e.slug})),Object.assign(t,ge.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,ge.createIncomingCallLambda({slug:e.slug,roleArn:r,notificationTopicArn:i,callLogTable:s,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(t,ge.createVoicemailLambda({slug:e.slug,roleArn:r,voicemailBucket:a,notificationTopicArn:i,callLogTable:s,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(t,ge.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 ae{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:p=!0,kmsKeyId:m}=e,g=r||b({slug:t,environment:n,resourceType:"queue"}),y=l?`${g}.fifo`:g,f=h(g),S={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)S.Properties.FifoQueue=!0,S.Properties.ContentBasedDeduplication=u;if(p)if(m)S.Properties.KmsMasterKeyId=m;else S.Properties.SqsManagedSseEnabled=!0;return{queue:S,logicalId:f}}static createDeadLetterQueue(e,t){let{slug:n,environment:r,maxReceiveCount:i=3}=t,s=b({slug:n,environment:r,resourceType:"dlq"}),a=h(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||b({slug:n,environment:r,resourceType:"schedule"}),c=h(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:p=[],assignPublicIp:m=!1,taskCount:g=1,containerOverrides:y}=n,f=s||b({slug:r,environment:i,resourceType:"ecs-schedule"}),S=h(f),T={Id:"1",Arn:l,RoleArn:t,EcsParameters:{TaskDefinitionArn:c,TaskCount:g,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:u,SecurityGroups:p,AssignPublicIp:m?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(y&&y.length>0)T.Input=JSON.stringify({containerOverrides:y});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:f,Description:a||`Scheduled ECS task: ${c}`,ScheduleExpression:e,State:o?"ENABLED":"DISABLED",Targets:[T]}},logicalId:S}}static scheduleLambda(e,t){let{slug:n,environment:r,name:i,description:s,enabled:a=!0,functionArn:o,input:c}=t,l=i||b({slug:n,environment:r,resourceType:"lambda-schedule"}),u=h(l),p={Id:"1",Arn:o};if(c)p.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:[p]}},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||b({slug:n,environment:r,resourceType:"sqs-schedule"}),u=h(l),p={Id:"1",Arn:o};if(c)p.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:[p]}},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(),p=u.endsWith("s")&&l===1?u.slice(0,-1):u,m=!u.endsWith("s")&&l>1?`${u}s`:u;return`rate(${l} ${l===1?p:m})`}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 ae.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:p="app"}=e,m=ae.rateStringToExpression(r),g=ae.createJobContainerOverride({containerName:p,jobClass:i,jobData:s});return ae.scheduleEcsTask(m,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)=>ae.createQueue({slug:e,environment:t,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,t)=>ae.createQueue({slug:e,environment:t,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,t)=>ae.createQueue({slug:e,environment:t,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,t,n=60)=>ae.createQueue({slug:e,environment:t,delaySeconds:n})}}class Ae{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",""),p=s.readFileSync(l,"utf-8"),m=Ae.parseJobMetadata(p,u,l);if(m)i.push(m)}}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",""),p=s.readFileSync(l,"utf-8"),m=Ae.parseActionMetadata(p,u,l);if(m)i.push(m)}}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={},p=0;for(let m of r){if(!m.schedule||!m.enabled)continue;let{rule:g,logicalId:y}=ae.createScheduledJob({slug:t,environment:n,schedule:m.schedule,jobClass:m.name,taskDefinitionArn:i,clusterArn:s,subnets:a,securityGroups:o,roleArn:c,containerName:l});u[y]=g,p++}return{rules:u,count:p}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1661
|
+
`;class ye{static LambdaCode={incomingCall:jt,voicemail:dr,missedCall:ur};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 ae{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,f=h(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:f}}static createDeadLetterQueue(e,t){let{slug:n,environment:r,maxReceiveCount:i=3}=t,s=S({slug:n,environment:r,resourceType:"dlq"}),a=h(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=h(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,f=s||S({slug:r,environment:i,resourceType:"ecs-schedule"}),b=h(f),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:f,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=h(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=h(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 ae.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=ae.rateStringToExpression(r),g=ae.createJobContainerOverride({containerName:m,jobClass:i,jobData:s});return ae.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)=>ae.createQueue({slug:e,environment:t,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,t)=>ae.createQueue({slug:e,environment:t,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,t)=>ae.createQueue({slug:e,environment:t,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,t,n=60)=>ae.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}=ae.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
|
|
1662
1662
|
/**
|
|
1663
1663
|
* Job Runner Script
|
|
1664
1664
|
* This script is invoked by ECS scheduled tasks to run jobs
|
|
@@ -1703,7 +1703,7 @@ catch (error) {
|
|
|
1703
1703
|
}
|
|
1704
1704
|
|
|
1705
1705
|
run()
|
|
1706
|
-
`}static async generateJobManifest(e){let t=await
|
|
1706
|
+
`}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 Od={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 mr=`
|
|
1707
1707
|
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1708
1708
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1709
1709
|
|
|
@@ -1826,7 +1826,7 @@ catch (error) {
|
|
|
1826
1826
|
|
|
1827
1827
|
return { statusCode: 200, body: 'OK' };
|
|
1828
1828
|
};
|
|
1829
|
-
`;var
|
|
1829
|
+
`;var pr=`
|
|
1830
1830
|
const { DynamoDBClient, PutItemCommand, DeleteItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1831
1831
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1832
1832
|
|
|
@@ -1978,7 +1978,7 @@ catch (error) {
|
|
|
1978
1978
|
|
|
1979
1979
|
return { statusCode: 200, body: 'OK' };
|
|
1980
1980
|
};
|
|
1981
|
-
`;var
|
|
1981
|
+
`;var gr={};Oe(gr,{default:()=>ya,handler:()=>Kt});var Kt=`
|
|
1982
1982
|
const { PinpointClient, SendMessagesCommand } = require('@aws-sdk/client-pinpoint');
|
|
1983
1983
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1984
1984
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
@@ -2142,7 +2142,7 @@ function resolveTemplate(template, data) {
|
|
|
2142
2142
|
}
|
|
2143
2143
|
return result;
|
|
2144
2144
|
}
|
|
2145
|
-
`,
|
|
2145
|
+
`,ya=`
|
|
2146
2146
|
const { PinpointClient, SendMessagesCommand } = require('@aws-sdk/client-pinpoint');
|
|
2147
2147
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
2148
2148
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
@@ -2306,14 +2306,14 @@ function resolveTemplate(template, data) {
|
|
|
2306
2306
|
}
|
|
2307
2307
|
return result;
|
|
2308
2308
|
}
|
|
2309
|
-
`;class Q{static LambdaCode={send:_t,receive:rr,deliveryStatus:nr};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:Q.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:Q.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:Q.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,Q.createPinpointApp({slug:e.slug})),Object.assign(t,Q.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(t,Q.createSmsLambdaRole({slug:e.slug})),Object.assign(t,Q.createMessageLogTable({slug:e.slug})),Object.assign(t,Q.createOptOutTable({slug:e.slug})),Object.assign(t,Q.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,Q.createSendLambda({slug:e.slug,roleArn:r,pinpointAppId:i,messageLogTable:s,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(t,Q.createReceiveLambda({slug:e.slug,roleArn:r,optOutTable:a,messageLogTable:s,notificationTopicArn:o,webhookUrl:e.webhookUrl}));return Object.assign(t,Q.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 Wt(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((r)=>r.charAt(0).toUpperCase()+r.slice(1)).join("")||"User"}function ta(e,t){let n=(e||t).replace(/^\/+|\/+$/g,"");if(!n||n.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${t}`);return n}function na(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 ra(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 ia(e,t){return typeof e==="string"?`/${e}/${t}`:{"Fn::Sub":[`/\${FileSystemId}/${t}`,{FileSystemId:e}]}}function sa(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 aa{static create(e){let t=na(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=`${Wt(e.slug)}${Wt(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=Wt(c),p=ta(l.homeDirectory,c),m=`${i}${u}User`,g=l.roleArn;if(!g){let y=`${i}${u}Role`,f;if(t.type==="efs")f=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:sa(t.fileSystemId)}];else{let S=`arn:aws:s3:::${t.bucket}`;f=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:S,Condition:{StringLike:{"s3:prefix":[p,`${p}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${S}/${p}/*`}]}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:f}}]}},g={"Fn::GetAtt":[y,"Arn"]}}a[m]={Type:"AWS::Transfer::User",DependsOn:[s],Properties:{ServerId:{Ref:s},UserName:c,Role:g,HomeDirectoryType:"PATH",HomeDirectory:t.type==="efs"?ia(t.fileSystemId,p):`/${t.bucket}/${p}`,...t.type==="efs"?{PosixProfile:ra(c,l,t.posixProfile)}:{},SshPublicKeys:l.sshPublicKeys}}}return{resources:a,serverLogicalId:s,domain:n}}}class mt{static createBedrockRole(e,t){let{slug:n,environment:r,name:i,models:s=["*"],allowStreaming:a=!0}=t,o=i||b({slug:n,environment:r,resourceType:"bedrock-role"}),c=h(o),l=["bedrock:InvokeModel"];if(a)l.push("bedrock:InvokeModelWithResponseStream");let u=s.map((m)=>m==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${m}`);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||b({slug:t,environment:n,resourceType:"bedrock-policy"}),l=h(c),u=[];if(s)u.push("bedrock:InvokeModel");if(a)u.push("bedrock:InvokeModelWithResponseStream");if(o)u.push("bedrock:InvokeModelAsync");let p=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:p}]}}},logicalId:l}}static enableBedrockForLambda(e){return mt.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return mt.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return mt.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 Vt{static createPostgres(e){return Vt.createRDSInstance("postgres","16.2",e)}static createMysql(e){return Vt.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:p,securityGroupIds:m,encrypted:g=!0,kmsKeyId:y,multiAz:f=!1,backupRetentionDays:S=7,publiclyAccessible:v=!1,enableCloudwatchLogs:T=!0,deletionProtection:A=!0}=n,P=b({slug:r,environment:i,resourceType:`${e}-db`}),R=h(P),E,D;if(p&&p.length>0){let N=b({slug:r,environment:i,resourceType:"db-subnet-group"});D=h(N),E={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:N,DBSubnetGroupDescription:`Subnet group for ${P}`,SubnetIds:p,Tags:[{Key:"Name",Value:N},{Key:"Environment",Value:i}]}}}let w={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:P,DBInstanceClass:s,Engine:e,EngineVersion:t,MasterUsername:c,MasterUserPassword:l,AllocatedStorage:a,StorageType:o,StorageEncrypted:g,MultiAZ:f,BackupRetentionPeriod:S,PubliclyAccessible:v,DeletionProtection:A,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:i}]}};if(u)w.Properties.DBName=u;if(y)w.Properties.KmsKeyId=y;if(D)w.Properties.DBSubnetGroupName=C.Ref(D);if(m&&m.length>0)w.Properties.VPCSecurityGroups=m;if(T)w.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:w,subnetGroup:E,logicalId:R,subnetGroupId:D}}static createReadReplica(e,t){let{slug:n,environment:r,instanceClass:i="db.t3.micro",securityGroupIds:s,publiclyAccessible:a=!1}=t,o=b({slug:n,environment:r,resourceType:"db-replica"}),c=h(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=b({slug:r,environment:i,resourceType:"db-params"}),o=h(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:p=!0,kmsKeyId:m,pointInTimeRecovery:g=!0,ttlAttribute:y}=e,f=r||b({slug:t,environment:n,resourceType:"table"}),S=h(f),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:f,BillingMode:a,AttributeDefinitions:v,KeySchema:T,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:n}]}};if(a==="PROVISIONED")A.Properties.ProvisionedThroughput={ReadCapacityUnits:o,WriteCapacityUnits:c};if(l)A.Properties.StreamSpecification={StreamViewType:u};if(p)A.Properties.SSESpecification={SSEEnabled:!0,SSEType:m?"KMS":"AES256",KMSMasterKeyId:m};if(g)A.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(y)A.Properties.TimeToLiveSpecification={AttributeName:y,Enabled:!0};return{table:A,logicalId:S}}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((p)=>p.AttributeName===r.name))e.Properties.AttributeDefinitions.push({AttributeName:r.name,AttributeType:r.type});if(i&&!e.Properties.AttributeDefinitions.some((p)=>p.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 oa{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:p=!1,numNodeGroups:m=1,replicasPerNodeGroup:g=1,atRestEncryption:y=!0,transitEncryption:f=!0,authToken:S,kmsKeyId:v,snapshotRetentionDays:T=7,snapshotWindow:A,maintenanceWindow:P}=e,R=b({slug:t,environment:n,resourceType:"redis"}),E=h(R),D,w;if(a&&a.length>0){let k=b({slug:t,environment:n,resourceType:"cache-subnet-group"});w=h(k),D={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:k,Description:`Subnet group for ${R}`,SubnetIds:a,Tags:[{Key:"Name",Value:k},{Key:"Environment",Value:n}]}}}let N={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:R,ReplicationGroupDescription:`Redis cluster for ${t} ${n}`,Engine:"redis",EngineVersion:i,CacheNodeType:r,Port:s,AutomaticFailoverEnabled:l,MultiAZEnabled:u,AtRestEncryptionEnabled:y,TransitEncryptionEnabled:f,SnapshotRetentionLimit:T,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:n}]}};if(p)N.Properties.NumNodeGroups=m,N.Properties.ReplicasPerNodeGroup=g;else N.Properties.NumCacheClusters=c;if(S)N.Properties.AuthToken=S;if(v)N.Properties.KmsKeyId=v;if(w)N.Properties.CacheSubnetGroupName=C.Ref(w);if(o&&o.length>0)N.Properties.SecurityGroupIds=o;if(A)N.Properties.SnapshotWindow=A;if(P)N.Properties.PreferredMaintenanceWindow=P;return{replicationGroup:N,subnetGroup:D,logicalId:E,subnetGroupId:w}}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:p}=e,m=b({slug:t,environment:n,resourceType:"memcached"}),g=h(m),y,f;if(o&&o.length>0){let v=b({slug:t,environment:n,resourceType:"cache-subnet-group"});f=h(v),y={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:v,Description:`Subnet group for ${m}`,SubnetIds:o,Tags:[{Key:"Name",Value:v},{Key:"Environment",Value:n}]}}}let S={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:m,CacheNodeType:r,Engine:"memcached",EngineVersion:i,NumCacheNodes:a,Port:s,AZMode:l,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:n}]}};if(f)S.Properties.CacheSubnetGroupName=C.Ref(f);if(c&&c.length>0)S.Properties.VpcSecurityGroupIds=c;if(u&&u.length>0)S.Properties.PreferredAvailabilityZones=u;if(p)S.Properties.PreferredMaintenanceWindow=p;return{cluster:S,subnetGroup:y,logicalId:g,subnetGroupId:f}}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=b({slug:n,environment:r,resourceType:"redis-params"}),a=h(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=b({slug:n,environment:r,resourceType:"memcached-params"}),a=h(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 oe{static createUser(e){let{slug:t,environment:n,userName:r,groups:i,managedPolicyArns:s}=e,a=r||b({slug:t,environment:n,resourceType:"user"}),o=h(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||b({slug:t,environment:n,resourceType:"role"}),c=h(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||b({slug:t,environment:n,resourceType:"group"}),a=h(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||b({slug:t,environment:n,resourceType:"policy"}),o=h(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=b({slug:n,environment:r,resourceType:"access-key"}),a=h(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||b({slug:n,environment:r,resourceType:"instance-profile"}),a=h(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}=oe.createPolicy({slug:t,environment:n,policyName:b({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}=oe.createUser({slug:t,environment:n,userName:b({slug:t,environment:n,resourceType:"cicd-user"}),managedPolicyArns:[C.Ref(c)]});s[u]=l;let p,m;if(i){let g=oe.createAccessKey(u,{slug:t,environment:n});p=g.accessKey,m=g.logicalId,s[m]=p}return{user:l,accessKey:p,policy:o,userLogicalId:u,accessKeyLogicalId:m,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}=oe.createPolicy({slug:t,environment:n,policyName:b({slug:t,environment:n,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${t} (${n})`,statements:s});o[l]=c;let u=b({slug:t,environment:n,resourceType:"cross-account-role"}),p=h(u),m={};if(i)m.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(m).length>0?{Condition:m}:{}}]},ManagedPolicyArns:[C.Ref(l)],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n},{Key:"Purpose",Value:"Cross-Account Access"}]}};return o[p]=g,{role:g,policy:c,roleLogicalId:p,policyLogicalId:l,resources:o}}static createCliUser(e){let{slug:t,environment:n,permissions:r="readonly"}=e,i={},s=[],a=[];switch(r){case"readonly":a=[oe.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=[oe.ManagedPolicies.AdministratorAccess];break}let o,c;if(s.length>0){let g=oe.createPolicy({slug:t,environment:n,policyName:b({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}=oe.createUser({slug:t,environment:n,userName:b({slug:t,environment:n,resourceType:"cli-user"}),managedPolicyArns:a});i[u]=l;let{accessKey:p,logicalId:m}=oe.createAccessKey(u,{slug:t,environment:n});return i[m]=p,{user:l,accessKey:p,policy:o,userLogicalId:u,accessKeyLogicalId:m,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 ca{static createRestApi(e){let{slug:t,environment:n,name:r,description:i,endpointType:s="REGIONAL",binaryMediaTypes:a,compressionSize:o}=e,c=r||b({slug:t,environment:n,resourceType:"rest-api"}),l=h(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,p=r||b({slug:t,environment:n,resourceType:"http-api"}),m=h(p),g={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:p,Description:i||`HTTP API for ${t} ${n}`,ProtocolType:"HTTP",Tags:{Name:p,Environment:n}}};if(s)g.Properties.CorsConfiguration={AllowOrigins:a,AllowMethods:o,AllowHeaders:c,MaxAge:l,AllowCredentials:u};return{httpApi:g,logicalId:m}}static createWebSocketApi(e){let{slug:t,environment:n,name:r,description:i}=e,s=r||b({slug:t,environment:n,resourceType:"ws-api"}),a=h(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=b({slug:n,environment:r,resourceType:"api-deployment"}),a=h(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,p=b({slug:r,environment:i,resourceType:"api-stage"}),m=h(p),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:p},{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:m}}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||b({slug:n,environment:r,resourceType:"api-authorizer"}),p=h(u),m={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");m.Properties.AuthorizerUri=a,m.Properties.IdentitySource=o||"method.request.header.Authorization"}if(s==="COGNITO_USER_POOLS"){if(!c||c.length===0)throw Error("Cognito authorizer requires userPoolArns");m.Properties.ProviderARNs=c,m.Properties.IdentitySource=o||"method.request.header.Authorization"}return{authorizer:m,logicalId:p}}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 ee{static createTopic(e){let{slug:t,environment:n,topicName:r,displayName:i,encrypted:s=!1,kmsKeyId:a}=e,o=r||b({slug:t,environment:n,resourceType:"topic"}),c=h(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=b({slug:n,environment:r,resourceType:"subscription"}),l=s.replace(/[^a-zA-Z0-9]/g,""),u=l.length>12?l.slice(-12):l,p=h(`${c}-${i}-${u}`),m={Type:"AWS::SNS::Subscription",Properties:{TopicArn:C.Ref(e),Protocol:i,Endpoint:s,RawMessageDelivery:o}};if(a)m.Properties.FilterPolicy=a;return{subscription:m,logicalId:p}}static subscribeEmail(e,t,n){return ee.subscribe(e,{...n,protocol:"email",endpoint:t})}static subscribeLambda(e,t,n){return ee.subscribe(e,{...n,protocol:"lambda",endpoint:t,rawMessageDelivery:!0})}static subscribeSqs(e,t,n){return ee.subscribe(e,{...n,protocol:"sqs",endpoint:t})}static subscribeHttp(e,t,n){let r=t.startsWith("https://")?"https":"http";return ee.subscribe(e,{...n,protocol:r,endpoint:t})}static subscribeSms(e,t,n){return ee.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=b({slug:n,environment:r,resourceType:"topic-policy"}),c=h(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 ee.setTopicPolicy(e,{...t,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,t){return ee.setTopicPolicy(e,{...t,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,t){return ee.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)=>ee.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>ee.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>ee.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class la{static createStateMachine(e){let{slug:t,environment:n,stateMachineName:r,type:i="STANDARD",definition:s,roleArn:a,loggingConfiguration:o,tracingConfiguration:c}=e,l=r||b({slug:t,environment:n,resourceType:"state-machine"}),u=h(l),p,m,g;if(a)g=a;else{let f=b({slug:t,environment:n,resourceType:"state-machine-role"});m=h(f),p={Type:"AWS::IAM::Role",Properties:{RoleName:f,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:f},{Key:"Environment",Value:n}]}},g=C.GetAtt(m,"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((f)=>({CloudWatchLogsLogGroup:{LogGroupArn:f}}))};if(c)y.Properties.TracingConfiguration={Enabled:c.enabled};return{stateMachine:y,logicalId:u,role:p,roleLogicalId:m}}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 sr{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:p="notBreaching",actionsEnabled:m=!0,alarmActions:g,okActions:y,insufficientDataActions:f,dimensions:S,unit:v,datapointsToAlarm:T}=e,A=r||b({slug:t,environment:n,resourceType:"alarm"}),P=h(A),R={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:A,MetricName:i,Namespace:s,Statistic:a,Period:o,EvaluationPeriods:c,Threshold:l,ComparisonOperator:u,TreatMissingData:p,ActionsEnabled:m}};if(g&&g.length>0)R.Properties.AlarmActions=g;if(y&&y.length>0)R.Properties.OKActions=y;if(f&&f.length>0)R.Properties.InsufficientDataActions=f;if(S)R.Properties.Dimensions=Object.entries(S).map(([E,D])=>({Name:E,Value:D}));if(v)R.Properties.Unit=v;if(T!==void 0)R.Properties.DatapointsToAlarm=T;return{alarm:R,logicalId:P}}static createCompositeAlarm(e){let{slug:t,environment:n,alarmName:r,alarmRule:i,actionsEnabled:s=!0,alarmActions:a,okActions:o,insufficientDataActions:c}=e,l=r||b({slug:t,environment:n,resourceType:"composite-alarm"}),u=h(l),p={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:l,AlarmRule:i,ActionsEnabled:s}};if(a&&a.length>0)p.Properties.AlarmActions=a;if(o&&o.length>0)p.Properties.OKActions=o;if(c&&c.length>0)p.Properties.InsufficientDataActions=c;return{alarm:p,logicalId:u}}static createDashboard(e){let{slug:t,environment:n,dashboardName:r,widgets:i}=e,s=r||b({slug:t,environment:n,resourceType:"dashboard"}),a=h(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||b({slug:t,environment:n,resourceType:"log-group"}),o=h(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||b({slug:n,environment:r,resourceType:"log-stream"}),a=h(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||b({slug:n,environment:r,resourceType:"metric-filter"}),c=h(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 '")}'
|
|
2309
|
+
`;class Q{static LambdaCode={send:Kt,receive:pr,deliveryStatus:mr};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:Q.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:Q.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:Q.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,Q.createPinpointApp({slug:e.slug})),Object.assign(t,Q.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(t,Q.createSmsLambdaRole({slug:e.slug})),Object.assign(t,Q.createMessageLogTable({slug:e.slug})),Object.assign(t,Q.createOptOutTable({slug:e.slug})),Object.assign(t,Q.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,Q.createSendLambda({slug:e.slug,roleArn:r,pinpointAppId:i,messageLogTable:s,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(t,Q.createReceiveLambda({slug:e.slug,roleArn:r,optOutTable:a,messageLogTable:s,notificationTopicArn:o,webhookUrl:e.webhookUrl}));return Object.assign(t,Q.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 ha(e,t){let n=(e||t).replace(/^\/+|\/+$/g,"");if(!n||n.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${t}`);return n}function fa(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 ba(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 Sa(e,t){return typeof e==="string"?`/${e}/${t}`:{"Fn::Sub":[`/\${FileSystemId}/${t}`,{FileSystemId:e}]}}function Aa(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 Ca{static create(e){let t=fa(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=ha(l.homeDirectory,c),p=`${i}${u}User`,g=l.roleArn;if(!g){let y=`${i}${u}Role`,f;if(t.type==="efs")f=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Aa(t.fileSystemId)}];else{let b=`arn:aws:s3:::${t.bucket}`;f=[{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:f}}]}},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"?Sa(t.fileSystemId,m):`/${t.bucket}/${m}`,...t.type==="efs"?{PosixProfile:ba(c,l,t.posixProfile)}:{},SshPublicKeys:l.sshPublicKeys}}}return{resources:a,serverLogicalId:s,domain:n}}}class ft{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=h(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=h(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 ft.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return ft.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return ft.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:f=!1,backupRetentionDays:b=7,publiclyAccessible:v=!1,enableCloudwatchLogs:T=!0,deletionProtection:A=!0}=n,P=S({slug:r,environment:i,resourceType:`${e}-db`}),R=h(P),E,D;if(m&&m.length>0){let N=S({slug:r,environment:i,resourceType:"db-subnet-group"});D=h(N),E={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:N,DBSubnetGroupDescription:`Subnet group for ${P}`,SubnetIds:m,Tags:[{Key:"Name",Value:N},{Key:"Environment",Value:i}]}}}let w={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:P,DBInstanceClass:s,Engine:e,EngineVersion:t,MasterUsername:c,MasterUserPassword:l,AllocatedStorage:a,StorageType:o,StorageEncrypted:g,MultiAZ:f,BackupRetentionPeriod:b,PubliclyAccessible:v,DeletionProtection:A,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:i}]}};if(u)w.Properties.DBName=u;if(y)w.Properties.KmsKeyId=y;if(D)w.Properties.DBSubnetGroupName=C.Ref(D);if(p&&p.length>0)w.Properties.VPCSecurityGroups=p;if(T)w.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:w,subnetGroup:E,logicalId:R,subnetGroupId:D}}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=h(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=h(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,f=r||S({slug:t,environment:n,resourceType:"table"}),b=h(f),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:f,BillingMode:a,AttributeDefinitions:v,KeySchema:T,Tags:[{Key:"Name",Value:f},{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 va{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:f=!0,authToken:b,kmsKeyId:v,snapshotRetentionDays:T=7,snapshotWindow:A,maintenanceWindow:P}=e,R=S({slug:t,environment:n,resourceType:"redis"}),E=h(R),D,w;if(a&&a.length>0){let k=S({slug:t,environment:n,resourceType:"cache-subnet-group"});w=h(k),D={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:k,Description:`Subnet group for ${R}`,SubnetIds:a,Tags:[{Key:"Name",Value:k},{Key:"Environment",Value:n}]}}}let N={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:R,ReplicationGroupDescription:`Redis cluster for ${t} ${n}`,Engine:"redis",EngineVersion:i,CacheNodeType:r,Port:s,AutomaticFailoverEnabled:l,MultiAZEnabled:u,AtRestEncryptionEnabled:y,TransitEncryptionEnabled:f,SnapshotRetentionLimit:T,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:n}]}};if(m)N.Properties.NumNodeGroups=p,N.Properties.ReplicasPerNodeGroup=g;else N.Properties.NumCacheClusters=c;if(b)N.Properties.AuthToken=b;if(v)N.Properties.KmsKeyId=v;if(w)N.Properties.CacheSubnetGroupName=C.Ref(w);if(o&&o.length>0)N.Properties.SecurityGroupIds=o;if(A)N.Properties.SnapshotWindow=A;if(P)N.Properties.PreferredMaintenanceWindow=P;return{replicationGroup:N,subnetGroup:D,logicalId:E,subnetGroupId:w}}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=h(p),y,f;if(o&&o.length>0){let v=S({slug:t,environment:n,resourceType:"cache-subnet-group"});f=h(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(f)b.Properties.CacheSubnetGroupName=C.Ref(f);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:f}}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=h(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=h(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 oe{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=h(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=h(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=h(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=h(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=h(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=h(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}=oe.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}=oe.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=oe.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}=oe.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=h(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=[oe.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=[oe.ManagedPolicies.AdministratorAccess];break}let o,c;if(s.length>0){let g=oe.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}=oe.createUser({slug:t,environment:n,userName:S({slug:t,environment:n,resourceType:"cli-user"}),managedPolicyArns:a});i[u]=l;let{accessKey:m,logicalId:p}=oe.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 Ta{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=h(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=h(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=h(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=h(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=h(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=h(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 ee{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=h(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=h(`${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 ee.subscribe(e,{...n,protocol:"email",endpoint:t})}static subscribeLambda(e,t,n){return ee.subscribe(e,{...n,protocol:"lambda",endpoint:t,rawMessageDelivery:!0})}static subscribeSqs(e,t,n){return ee.subscribe(e,{...n,protocol:"sqs",endpoint:t})}static subscribeHttp(e,t,n){let r=t.startsWith("https://")?"https":"http";return ee.subscribe(e,{...n,protocol:r,endpoint:t})}static subscribeSms(e,t,n){return ee.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=h(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 ee.setTopicPolicy(e,{...t,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,t){return ee.setTopicPolicy(e,{...t,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,t){return ee.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)=>ee.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>ee.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>ee.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class Ra{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=h(l),m,p,g;if(a)g=a;else{let f=S({slug:t,environment:n,resourceType:"state-machine-role"});p=h(f),m={Type:"AWS::IAM::Role",Properties:{RoleName:f,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:f},{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((f)=>({CloudWatchLogsLogGroup:{LogGroupArn:f}}))};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 yr{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:f,dimensions:b,unit:v,datapointsToAlarm:T}=e,A=r||S({slug:t,environment:n,resourceType:"alarm"}),P=h(A),R={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)R.Properties.AlarmActions=g;if(y&&y.length>0)R.Properties.OKActions=y;if(f&&f.length>0)R.Properties.InsufficientDataActions=f;if(b)R.Properties.Dimensions=Object.entries(b).map(([E,D])=>({Name:E,Value:D}));if(v)R.Properties.Unit=v;if(T!==void 0)R.Properties.DatapointsToAlarm=T;return{alarm:R,logicalId:P}}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=h(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=h(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=h(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=h(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=h(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 '")}'
|
|
2310
2310
|
| fields @timestamp, @message
|
|
2311
2311
|
| sort @timestamp desc
|
|
2312
2312
|
| 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 '")}'
|
|
2313
2313
|
| fields @timestamp, @message
|
|
2314
2314
|
| filter @message like /ERROR|WARN|Exception/
|
|
2315
2315
|
| sort @timestamp desc
|
|
2316
|
-
| limit 50`,region:r,title:"Recent Errors and Warnings"}}),a+=6;return sr.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 J{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:p,accountRecoverySetting:m}=e,g=r||b({slug:t,environment:n,resourceType:"user-pool"}),y=h(g),f={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)f.Properties.UsernameAttributes=i;if(s&&s.length>0)f.Properties.AutoVerifiedAttributes=s;if(c)f.Properties.EmailConfiguration={EmailSendingAccount:c.emailSendingAccount,From:c.from,ReplyToEmailAddress:c.replyToEmailAddress,SourceArn:c.sourceArn,ConfigurationSet:c.configurationSet};if(l)f.Properties.SmsConfiguration={ExternalId:l.externalId,SnsCallerArn:l.snsCallerArn};if(u)f.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(p)f.Properties.UserPoolAddOns={AdvancedSecurityMode:p.advancedSecurityMode};if(m)f.Properties.AccountRecoverySetting={RecoveryMechanisms:m.recoveryMechanisms};return{userPool:f,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:p,explicitAuthFlows:m,preventUserExistenceErrors:g,enableTokenRevocation:y,callbackURLs:f,logoutURLs:S,allowedOAuthFlows:v,allowedOAuthScopes:T,allowedOAuthFlowsUserPoolClient:A,supportedIdentityProviders:P}=t,R=i||b({slug:n,environment:r,resourceType:"user-pool-client"}),E=h(R);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:R,UserPoolId:C.Ref(e),GenerateSecret:s,RefreshTokenValidity:a,AccessTokenValidity:o,IdTokenValidity:c,TokenValidityUnits:l,ReadAttributes:u,WriteAttributes:p,ExplicitAuthFlows:m,PreventUserExistenceErrors:g,EnableTokenRevocation:y,CallbackURLs:f,LogoutURLs:S,AllowedOAuthFlows:v,AllowedOAuthScopes:T,AllowedOAuthFlowsUserPoolClient:A,SupportedIdentityProviders:P}},logicalId:E}}static createUserPoolDomain(e,t){let{slug:n,environment:r,domain:i,customDomainConfig:s}=t,a=b({slug:n,environment:r,resourceType:"user-pool-domain"}),o=h(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||b({slug:t,environment:n,resourceType:"identity-pool"}),u=h(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=b({slug:n,environment:r,resourceType:"identity-pool-role-attachment"}),c=h(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=b({slug:t,environment:n,resourceType:"cognito-authenticated-role"}),s=h(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=b({slug:t,environment:n,resourceType:"cognito-unauthenticated-role"}),s=h(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}=J.createUserPool({slug:e,environment:t,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:J.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:s,logicalId:a}=J.createUserPoolClient(i,{slug:e,environment:t,explicitAuthFlows:[...J.AuthFlows.standard],callbackURLs:[n],allowedOAuthFlows:["code"],allowedOAuthScopes:[...J.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:r,poolId:i,client:s,clientId:a}},mobileApp:(e,t)=>{let{userPool:n,logicalId:r}=J.createUserPool({slug:e,environment:t,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:J.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:i,logicalId:s}=J.createUserPoolClient(r,{slug:e,environment:t,explicitAuthFlows:[...J.AuthFlows.standard]}),{identityPool:a,logicalId:o}=J.createIdentityPool({slug:e,environment:t,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:C.Ref(s),ProviderName:C.GetAtt(r,"ProviderName")}]}),{role:c,logicalId:l}=J.createAuthenticatedRole({slug:e,environment:t,identityPoolLogicalId:o}),{attachment:u,logicalId:p}=J.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:p}}}}import{createHash as ua}from"node:crypto";import{copyFileSync as da,existsSync as Ut,readdirSync as ma,readFileSync as pt,statSync as pa,writeFileSync as gt}from"node:fs";import{basename as ga,dirname as ar,extname as or,join as Ye}from"node:path";class Y{static createApplication(e){let{slug:t,environment:n,applicationName:r,computePlatform:i}=e,s=r||b({slug:t,environment:n,resourceType:"deploy-app"}),a=h(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:p,blueGreenDeploymentConfiguration:m}=t,g=i||b({slug:n,environment:r,resourceType:"deploy-group"}),y=h(g);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:C.Ref(e),DeploymentGroupName:g,ServiceRoleArn:s,AutoScalingGroups:a,Ec2TagFilters:o?.map((S)=>({Key:S.key,Value:S.value,Type:S.type})),DeploymentConfigName:c,AutoRollbackConfiguration:l?{Enabled:l.enabled,Events:l.events}:void 0,AlarmConfiguration:u?{Enabled:u.enabled,Alarms:u.alarms?.map((S)=>({Name:S.name})),IgnorePollAlarmFailure:u.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:p?{TargetGroupInfoList:p.targetGroupInfoList?.map((S)=>({Name:S.name})),ElbInfoList:p.elbInfoList?.map((S)=>({Name:S.name}))}:void 0,BlueGreenDeploymentConfiguration:m?{TerminateBlueInstancesOnDeploymentSuccess:m.terminateBlueInstancesOnDeploymentSuccess?{Action:m.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:m.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:m.deploymentReadyOption?{ActionOnTimeout:m.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:m.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:m.greenFleetProvisioningOption?{Action:m.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||b({slug:t,environment:n,resourceType:"deploy-config"}),o=h(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}=Y.createApplication({slug:e,environment:t,computePlatform:"Server"}),{deploymentGroup:a,logicalId:o}=Y.createDeploymentGroup(s,{slug:e,environment:t,serviceRoleArn:n,autoScalingGroups:r,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:Y.RollbackConfigs.onFailure()});return{application:i,appId:s,deploymentGroup:a,groupId:o}},lambdaCanaryDeployment:(e,t,n,r=10,i=5)=>{let{application:s,logicalId:a}=Y.createApplication({slug:e,environment:t,computePlatform:"Lambda"}),{deploymentConfig:o,logicalId:c}=Y.createDeploymentConfig({slug:e,environment:t,trafficRoutingConfig:Y.TrafficRouting.canary(r,i)}),{deploymentGroup:l,logicalId:u}=Y.createDeploymentGroup(a,{slug:e,environment:t,serviceRoleArn:n,deploymentConfigName:C.Ref(c),autoRollbackConfiguration:Y.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}=Y.createApplication({slug:e,environment:t,computePlatform:"ECS"}),{deploymentGroup:a,logicalId:o}=Y.createDeploymentGroup(s,{slug:e,environment:t,serviceRoleArn:n,loadBalancerInfo:{targetGroupInfoList:[{name:r}]},blueGreenDeploymentConfiguration:Y.BlueGreenConfigs.standard(),autoRollbackConfiguration:Y.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=pt(e);return ua(t).update(n).digest("hex")}static computeShortHash(e){return H.computeFileHash(e).slice(0,8)}static getContentType(e){let t=or(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=or(e),r=ga(e,n),i=ar(e);if(i===".")return`${r}.${t}${n}`;return Ye(i,`${r}.${t}${n}`)}static collectFiles(e,t){let n=[],r=t||e;if(!Ut(e))return n;let i=ma(e,{withFileTypes:!0});for(let s of i){let a=Ye(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 p=u.replace(t,"").replace(/^[/\\]/,""),m=H.shouldHashFile(p,r),g=pa(u),y=m?H.computeFileHash(u,i).slice(0,8):"",f=m?H.generateHashedFilename(p,y):p,S={originalPath:p,hashedPath:f,hash:y,size:g.size,contentType:H.getContentType(u)};if(o.push(S),c[p]=f,n){let v=Ye(n,f),T=ar(v);if(!Ut(T)){let{mkdirSync:A}=ws("node:fs");A(T,{recursive:!0})}if(m||s)da(u,v)}}let l={version:"1.0",timestamp:new Date().toISOString(),assets:o,hashMap:c};if(n){let u=Ye(n,"asset-manifest.json");gt(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=pt(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,(p)=>p.replace(o,c))}gt(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=pt(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})`)}gt(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:Ye(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(!Ut(e))return null;try{let t=pt(e,"utf-8");return JSON.parse(t)}catch{return null}}static saveManifest(e,t){gt(t,JSON.stringify(e,null,2))}}class Ze{static createSecret(e){let{slug:t,environment:n,secretName:r,description:i,secretString:s,kmsKeyId:a,tags:o}=e,c=r||b({slug:t,environment:n,resourceType:"secret"}),l=h(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(([p,m])=>({Key:p,Value:m})):[]]}};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:p,kmsKeyId:m,tags:g}=e,y=r||b({slug:t,environment:n,resourceType:"secret"}),f=h(y),S={Type:"AWS::SecretsManager::Secret",Properties:{Name:y,Description:i,GenerateSecretString:{ExcludeCharacters:s,ExcludeLowercase:a,ExcludeNumbers:o,ExcludePunctuation:c,ExcludeUppercase:l,PasswordLength:u||32,RequireEachIncludedType:p!==!1},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:n},...g?Object.entries(g).map(([v,T])=>({Key:v,Value:T})):[]]}};if(m)S.Properties.KmsKeyId=m;return{secret:S,logicalId:f}}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||b({slug:t,environment:n,resourceType:"db-secret"}),p=h(u),m={username:i};if(s)m.dbname=s;if(a)m.engine=a;if(o)m.host=o;if(c)m.port=c;let g={Type:"AWS::SecretsManager::Secret",Properties:{Name:u,Description:`Database credentials for ${i}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(m),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:p}}static attachToDatabase(e){let{slug:t,environment:n,secretId:r,targetId:i,targetType:s}=e,a=b({slug:t,environment:n,resourceType:"secret-attachment"}),o=h(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=b({slug:t,environment:n,resourceType:"secret-rotation"}),p=h(u),m={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:r,RotationRules:{AutomaticallyAfterDays:s||30}}};if(i)m.Properties.RotationLambdaARN=i;else if(a)m.Properties.HostedRotationLambda={RotationType:a,KmsKeyArn:o,VpcSecurityGroupIds:c,VpcSubnetIds:l};return{rotation:m,logicalId:p}}static SecretTypes={apiKey:(e,t,n)=>Ze.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)=>Ze.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)=>Ze.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,t)=>Ze.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||b({slug:t,environment:n,resourceType:"parameter"}),u=h(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 Xe{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:p=3,multiAz:m=!1,availabilityZoneCount:g=2,vpc:y,encryption:f,enforceHttps:S=!0,tlsSecurityPolicy:v="Policy-Min-TLS-1-2-2019-07",advancedSecurity:T,autoSnapshotHour:A=0,autoTune:P=!0,tags:R={}}=e,E=r||b({slug:t,environment:n,resourceType:"search"}),D=h(E);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:E,EngineVersion:i,ClusterConfig:{InstanceType:s,InstanceCount:a,DedicatedMasterEnabled:l,...l&&{DedicatedMasterType:u||s,DedicatedMasterCount:p},ZoneAwarenessEnabled:m,...m&&{ZoneAwarenessConfig:{AvailabilityZoneCount:g}}},EBSOptions:{EBSEnabled:!0,VolumeType:c,VolumeSize:o},DomainEndpointOptions:{EnforceHTTPS:S,TLSSecurityPolicy:v},SnapshotOptions:{AutomatedSnapshotStartHour:A},...y&&{VPCOptions:{SubnetIds:y.subnetIds,SecurityGroupIds:y.securityGroupIds}},...f&&{EncryptionAtRestOptions:{Enabled:f.atRest??!0,...f.kmsKeyId&&{KmsKeyId:f.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:f.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}}}},...P&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:n},...Object.entries(R).map(([N,k])=>({Key:N,Value:k}))]}},logicalId:D}}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)=>Xe.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)=>Xe.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)=>Xe.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)=>Xe.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 yt{static createDomainRedirectBucket(e){let{slug:t,environment:n,sourceDomain:r,targetDomain:i,protocol:s="https"}=e,a=b({slug:t,environment:n,resourceType:"s3",suffix:"redirect"}),o=h(a),c=h(`${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=b({slug:t,environment:n,resourceType:"cf-redirect"}),s=h(i),a=yt.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) {
|
|
2316
|
+
| limit 50`,region:r,title:"Recent Errors and Warnings"}}),a+=6;return yr.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 J{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=h(g),f={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)f.Properties.UsernameAttributes=i;if(s&&s.length>0)f.Properties.AutoVerifiedAttributes=s;if(c)f.Properties.EmailConfiguration={EmailSendingAccount:c.emailSendingAccount,From:c.from,ReplyToEmailAddress:c.replyToEmailAddress,SourceArn:c.sourceArn,ConfigurationSet:c.configurationSet};if(l)f.Properties.SmsConfiguration={ExternalId:l.externalId,SnsCallerArn:l.snsCallerArn};if(u)f.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)f.Properties.UserPoolAddOns={AdvancedSecurityMode:m.advancedSecurityMode};if(p)f.Properties.AccountRecoverySetting={RecoveryMechanisms:p.recoveryMechanisms};return{userPool:f,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:f,logoutURLs:b,allowedOAuthFlows:v,allowedOAuthScopes:T,allowedOAuthFlowsUserPoolClient:A,supportedIdentityProviders:P}=t,R=i||S({slug:n,environment:r,resourceType:"user-pool-client"}),E=h(R);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:R,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:f,LogoutURLs:b,AllowedOAuthFlows:v,AllowedOAuthScopes:T,AllowedOAuthFlowsUserPoolClient:A,SupportedIdentityProviders:P}},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=h(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=h(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=h(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=h(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=h(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}=J.createUserPool({slug:e,environment:t,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:J.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:s,logicalId:a}=J.createUserPoolClient(i,{slug:e,environment:t,explicitAuthFlows:[...J.AuthFlows.standard],callbackURLs:[n],allowedOAuthFlows:["code"],allowedOAuthScopes:[...J.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:r,poolId:i,client:s,clientId:a}},mobileApp:(e,t)=>{let{userPool:n,logicalId:r}=J.createUserPool({slug:e,environment:t,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:J.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:i,logicalId:s}=J.createUserPoolClient(r,{slug:e,environment:t,explicitAuthFlows:[...J.AuthFlows.standard]}),{identityPool:a,logicalId:o}=J.createIdentityPool({slug:e,environment:t,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:C.Ref(s),ProviderName:C.GetAtt(r,"ProviderName")}]}),{role:c,logicalId:l}=J.createAuthenticatedRole({slug:e,environment:t,identityPoolLogicalId:o}),{attachment:u,logicalId:m}=J.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 Pa}from"node:crypto";import{copyFileSync as Ea,existsSync as Qt,readdirSync as wa,readFileSync as bt,statSync as Ia,writeFileSync as St}from"node:fs";import{basename as Da,dirname as hr,extname as fr,join as et}from"node:path";class Y{static createApplication(e){let{slug:t,environment:n,applicationName:r,computePlatform:i}=e,s=r||S({slug:t,environment:n,resourceType:"deploy-app"}),a=h(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=h(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=h(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}=Y.createApplication({slug:e,environment:t,computePlatform:"Server"}),{deploymentGroup:a,logicalId:o}=Y.createDeploymentGroup(s,{slug:e,environment:t,serviceRoleArn:n,autoScalingGroups:r,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:Y.RollbackConfigs.onFailure()});return{application:i,appId:s,deploymentGroup:a,groupId:o}},lambdaCanaryDeployment:(e,t,n,r=10,i=5)=>{let{application:s,logicalId:a}=Y.createApplication({slug:e,environment:t,computePlatform:"Lambda"}),{deploymentConfig:o,logicalId:c}=Y.createDeploymentConfig({slug:e,environment:t,trafficRoutingConfig:Y.TrafficRouting.canary(r,i)}),{deploymentGroup:l,logicalId:u}=Y.createDeploymentGroup(a,{slug:e,environment:t,serviceRoleArn:n,deploymentConfigName:C.Ref(c),autoRollbackConfiguration:Y.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}=Y.createApplication({slug:e,environment:t,computePlatform:"ECS"}),{deploymentGroup:a,logicalId:o}=Y.createDeploymentGroup(s,{slug:e,environment:t,serviceRoleArn:n,loadBalancerInfo:{targetGroupInfoList:[{name:r}]},blueGreenDeploymentConfiguration:Y.BlueGreenConfigs.standard(),autoRollbackConfiguration:Y.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 Pa(t).update(n).digest("hex")}static computeShortHash(e){return H.computeFileHash(e).slice(0,8)}static getContentType(e){let t=fr(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=fr(e),r=Da(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=wa(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=Ia(u),y=p?H.computeFileHash(u,i).slice(0,8):"",f=p?H.generateHashedFilename(m,y):m,b={originalPath:m,hashedPath:f,hash:y,size:g.size,contentType:H.getContentType(u)};if(o.push(b),c[m]=f,n){let v=et(n,f),T=hr(v);if(!Qt(T)){let{mkdirSync:A}=Bs("node:fs");A(T,{recursive:!0})}if(p||s)Ea(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=h(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"}),f=h(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:f}}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=h(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=h(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=h(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=h(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:f,enforceHttps:b=!0,tlsSecurityPolicy:v="Policy-Min-TLS-1-2-2019-07",advancedSecurity:T,autoSnapshotHour:A=0,autoTune:P=!0,tags:R={}}=e,E=r||S({slug:t,environment:n,resourceType:"search"}),D=h(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}},...f&&{EncryptionAtRestOptions:{Enabled:f.atRest??!0,...f.kmsKeyId&&{KmsKeyId:f.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:f.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}}}},...P&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:n},...Object.entries(R).map(([N,k])=>({Key:N,Value:k}))]}},logicalId:D}}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=h(a),c=h(`${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=h(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) {
|
|
2317
2317
|
const request = event.request;
|
|
2318
2318
|
const uri = request.uri;
|
|
2319
2319
|
const querystring = request.querystring;
|
|
@@ -2367,7 +2367,7 @@ ${e.map((n)=>{let r=n.preserveQueryString!==!1,i=n.statusCode||301;return` '${n
|
|
|
2367
2367
|
}
|
|
2368
2368
|
|
|
2369
2369
|
return request;
|
|
2370
|
-
}`}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:p,policyLogicalId:m}=yt.createDomainRedirectBucket({...c,slug:t,environment:n});s[p]=l,s[m]=u,a.push(p)}let o=null;if(i.length>0){let{function:c,logicalId:l}=yt.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 Z{static generate(e){let t={},{slug:n,environment:r,region:i="us-east-1"}=e,s=Z.createLambdaExecutionRole(n,r);if(Object.assign(t,s.resources),e.email?.enabled){let a=Z.generateEmailResources(e,s.roleArn);Object.assign(t,a)}if(e.phone?.enabled){let a=Z.generatePhoneResources(e,s.roleArn);Object.assign(t,a)}if(e.sms?.enabled){let a=Z.generateSmsResources(e,s.roleArn);Object.assign(t,a)}return t}static createLambdaExecutionRole(e,t){let n=`${e}-${t}-communication-role`,r=h(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=h(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=h(`${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=h(`${a}-bounce-topic`);s[u]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-email-bounces`}};let p=h(`${a}-complaint-topic`);s[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-email-complaints`}}}if(i.server?.enabled){let u=h(`${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:Z.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:o,DOMAIN:i.domain}}}};let p=h(`${a}-outbound-email`);s[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:Z.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:o,DOMAIN:i.domain}}}}}if(i.advanced?.analytics){let u=h(`${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=h(`${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:Z.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:o}}}};let p=h(`${a}-email-scheduler-rule`);s[p]={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=h(`${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:Z.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:o}}}}}if(i.advanced?.rules){let u=h(`${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=h(`${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=h(`${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=h(`${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=h(`${a}-voicemail`);s[u]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${a}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let c=h(`${a}-phone-notifications`);s[c]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-phone-notifications`}};let l=h(`${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:Z.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${a}-call-log`,NOTIFICATION_TOPIC_ARN:C.Ref(c)}}}},i.voicemail?.enabled){let u=h(`${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:Z.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=h(`${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=h(`${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=h(`${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=h(`${a}-pinpoint-app`);s[o]={Type:"AWS::Pinpoint::App",Properties:{Name:`${a}-sms`}};let c=h(`${a}-sms-channel`);s[c]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:C.Ref(o),Enabled:!0,SenderId:i.senderId}};let l=h(`${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=h(`${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=h(`${a}-sms-notifications`);s[u]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-sms-notifications`}};let p=h(`${a}-send-sms`);s[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:Z.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 m=h(`${a}-receive-sms`);if(s[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${a}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:Z.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=h(`${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=h(`${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=h(`${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=h(`${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=h(`${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=h(`${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=h(`${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=`
|
|
2370
|
+
}`}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 Z{static generate(e){let t={},{slug:n,environment:r,region:i="us-east-1"}=e,s=Z.createLambdaExecutionRole(n,r);if(Object.assign(t,s.resources),e.email?.enabled){let a=Z.generateEmailResources(e,s.roleArn);Object.assign(t,a)}if(e.phone?.enabled){let a=Z.generatePhoneResources(e,s.roleArn);Object.assign(t,a)}if(e.sms?.enabled){let a=Z.generateSmsResources(e,s.roleArn);Object.assign(t,a)}return t}static createLambdaExecutionRole(e,t){let n=`${e}-${t}-communication-role`,r=h(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=h(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=h(`${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=h(`${a}-bounce-topic`);s[u]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-email-bounces`}};let m=h(`${a}-complaint-topic`);s[m]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-email-complaints`}}}if(i.server?.enabled){let u=h(`${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:Z.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:o,DOMAIN:i.domain}}}};let m=h(`${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:Z.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:o,DOMAIN:i.domain}}}}}if(i.advanced?.analytics){let u=h(`${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=h(`${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:Z.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:o}}}};let m=h(`${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=h(`${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:Z.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:o}}}}}if(i.advanced?.rules){let u=h(`${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=h(`${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=h(`${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=h(`${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=h(`${a}-voicemail`);s[u]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${a}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let c=h(`${a}-phone-notifications`);s[c]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-phone-notifications`}};let l=h(`${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:Z.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${a}-call-log`,NOTIFICATION_TOPIC_ARN:C.Ref(c)}}}},i.voicemail?.enabled){let u=h(`${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:Z.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=h(`${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=h(`${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=h(`${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=h(`${a}-pinpoint-app`);s[o]={Type:"AWS::Pinpoint::App",Properties:{Name:`${a}-sms`}};let c=h(`${a}-sms-channel`);s[c]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:C.Ref(o),Enabled:!0,SenderId:i.senderId}};let l=h(`${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=h(`${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=h(`${a}-sms-notifications`);s[u]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${a}-sms-notifications`}};let m=h(`${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:Z.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=h(`${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:Z.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=h(`${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=h(`${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=h(`${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=h(`${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=h(`${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=h(`${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=h(`${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=`
|
|
2371
2371
|
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
2372
2372
|
const s3 = new S3Client({});
|
|
2373
2373
|
exports.handler = async (event) => {
|
|
@@ -2465,7 +2465,7 @@ exports.handler = async (event) => {
|
|
|
2465
2465
|
console.log('Receive SMS:', JSON.stringify(event, null, 2));
|
|
2466
2466
|
// Process inbound SMS, handle opt-out keywords
|
|
2467
2467
|
return { statusCode: 200 };
|
|
2468
|
-
};`}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}`)},Wm={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 cr(e,t){if(t.type==="http")ya(e,t);else if(t.type==="rest")ha(e,t);else if(t.type==="websocket")fa(e,t)}function ya(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)Ht(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 ha(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)Ht(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 fa(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)ht(e,"$connect",t.routes.connect.functionName);if(t.routes.disconnect)ht(e,"$disconnect",t.routes.disconnect.functionName);if(t.routes.default)ht(e,"$default",t.routes.default.functionName);if(t.routes.custom)t.routes.custom.forEach((n)=>{ht(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)Ht(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 ht(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 Ht(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(`${Sa(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 Sa(e){let t=e.split(".");if(t.length>=2)return t.slice(-2).join(".");return e}function lr(e,t){if(t.redis)Aa(e,t.redis);if(t.memcached)Ca(e,t.memcached);if(t.elasticache)va(e,t.elasticache)}function Aa(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 Ca(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 va(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 ur(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(`${Ta(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 Ta(e){let t=e.split(".");if(t.length>=2)return t.slice(-2).join(".");return e}function mr(e,t){if(t.server)Ra(e,t.server);if(t.fargate)dr(e,"app",t.fargate);if(t.services)t.services.forEach((n)=>{if(n.type==="fargate")dr(e,n.name,{taskDefinition:n.taskDefinition,service:n.service})})}function Ra(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
|
|
2468
|
+
};`}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}`)},dp={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 br(e,t){if(t.type==="http")Na(e,t);else if(t.type==="rest")xa(e,t);else if(t.type==="websocket")ka(e,t)}function Na(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)Ma(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 xa(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 ka(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(`${La(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 Ma(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 La(e){let t=e.split(".");if(t.length>=2)return t.slice(-2).join(".");return e}function Sr(e,t){if(t.redis)Oa(e,t.redis);if(t.memcached)$a(e,t.memcached);if(t.elasticache)Ba(e,t.elasticache)}function Oa(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 Ba(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 Ar(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(`${Fa(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 Fa(e){let t=e.split(".");if(t.length>=2)return t.slice(-2).join(".");return e}function vr(e,t){if(t.server)Ga(e,t.server);if(t.fargate)Cr(e,"app",t.fargate);if(t.services)t.services.forEach((n)=>{if(n.type==="fargate")Cr(e,n.name,{taskDefinition:n.taskDefinition,service:n.service})})}function Ga(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
|
|
2469
2469
|
set -e
|
|
2470
2470
|
# Update system
|
|
2471
2471
|
yum update -y || apt-get update -y
|
|
@@ -2480,20 +2480,20 @@ rpm -U ./amazon-cloudwatch-agent.rpm || true
|
|
|
2480
2480
|
|
|
2481
2481
|
# Signal completion
|
|
2482
2482
|
/opt/aws/bin/cfn-signal -e $? --stack \${AWS::StackName} --resource AutoScalingGroup --region \${AWS::Region}
|
|
2483
|
-
`;if(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){Pa(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 Pa(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 dr(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((m)=>(m.secrets||m.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((m)=>({Name:m.Name||m.name,Image:m.Image||m.image,Essential:m.Essential??m.essential??!0,PortMappings:(m.PortMappings||m.portMappings||[]).map((g)=>({ContainerPort:g.ContainerPort??g.containerPort,Protocol:g.Protocol||g.protocol||"tcp"})),Environment:Array.isArray(m.Environment||m.environment)?(m.Environment||m.environment).map((g)=>({Name:g.Name||g.name,Value:g.Value??g.value})):Object.entries(m.Environment||m.environment||{}).map(([g,y])=>({Name:g,Value:y})),Secrets:(m.Secrets||m.secrets||[]).map((g)=>({Name:g.Name||g.name,ValueFrom:g.ValueFrom||g.valueFrom})),HealthCheck:m.HealthCheck||m.healthCheck,Command:m.Command||m.command,EntryPoint:m.EntryPoint||m.entryPoint,LogConfiguration:m.LogConfiguration||m.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,p=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"}}]:p?[{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:p?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:d.ref(`${r}TargetGroup`)}]},{dependsOn:[`${r}LoadBalancer`,`${r}TargetGroup`]});if(p){let m=u?`${r}HttpsListener`:`${r}HttpListener`;e.addResource(`${r}OriginVerifyRule`,"AWS::ElasticLoadBalancingV2::ListenerRule",{ListenerArn:d.ref(m),Priority:1,Conditions:[{Field:"http-header",HttpHeaderConfig:{HttpHeaderName:p.name,Values:[p.value]}}],Actions:[{Type:"forward",TargetGroupArn:d.ref(`${r}TargetGroup`)}]},{dependsOn:[m,`${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`,p?`${r}OriginVerifyRule`:u?`${r}HttpsListener`:`${r}HttpListener`]}),n.service.autoScaling){let m=n.service.autoScaling;e.addResource(`${r}ScalableTarget`,"AWS::ApplicationAutoScaling::ScalableTarget",{MinCapacity:m.min,MaxCapacity:m.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:m.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 gr(e,t){if(t.postgres)pr(e,"postgres",t.postgres);if(t.mysql)pr(e,"mysql",t.mysql);if(t.dynamodb?.tables)t.dynamodb.tables.forEach((n)=>{Ea(e,n)})}function pr(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 Ea(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 yr(e,t){for(let[n,r]of Object.entries(t))r.forEach((i)=>{wa(e,i,n)})}function wa(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:[...Da(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) => {
|
|
2483
|
+
`;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){_a(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 _a(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 Cr(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 Rr(e,t){if(t.postgres)Tr(e,"postgres",t.postgres);if(t.mysql)Tr(e,"mysql",t.mysql);if(t.dynamodb?.tables)t.dynamodb.tables.forEach((n)=>{Wa(e,n)})}function Tr(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 Wa(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 Pr(e,t){for(let[n,r]of Object.entries(t))r.forEach((i)=>{Va(e,i,n)})}function Va(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:[...Ha(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) => {
|
|
2484
2484
|
console.log('Event:', JSON.stringify(event, null, 2));
|
|
2485
2485
|
return { statusCode: 200, body: 'Function not yet implemented' };
|
|
2486
|
-
};`},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)=>{
|
|
2486
|
+
};`},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)=>{Ua(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 Ua(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 Ha(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 Er(e,t){if(t.topics)t.topics.forEach((n)=>{ja(e,n)})}function ja(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 wr(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)=>{Ka(e,n,r)});if(t.dashboard)qa(e,t.dashboard);if(t.logs?.groups)t.logs.groups.forEach((n)=>{za(e,n,t.logs?.retention)})}function Ka(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=Qa(t.service);e.addResource(r,"AWS::CloudWatch::Alarm",i,{dependsOn:"AlarmTopic"})}function qa(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}'
|
|
2487
2487
|
| fields @timestamp, @message
|
|
2488
2488
|
| sort @timestamp desc
|
|
2489
|
-
| 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 Ma(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 jt(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 La(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 br(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 p=0;p<r;p++){let m=`PublicSubnet${p+1}`;o.push(m),e.addResource(m,"AWS::EC2::Subnet",{VpcId:d.ref("VPC"),CidrBlock:d.select(p,d.cidr(d.getAtt("VPC","CidrBlock"),r*2,8)),AvailabilityZone:d.select(p,d.getAZs()),MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-public-${p+1}`)},{Key:"Type",Value:"public"}]},{dependsOn:"VPC"})}let c=[];for(let p=0;p<r;p++){let m=`PrivateSubnet${p+1}`;c.push(m),e.addResource(m,"AWS::EC2::Subnet",{VpcId:d.ref("VPC"),CidrBlock:d.select(p+r,d.cidr(d.getAtt("VPC","CidrBlock"),r*2,8)),AvailabilityZone:d.select(p,d.getAZs()),MapPublicIpOnLaunch:!1,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-private-${p+1}`)},{Key:"Type",Value:"private"}]},{dependsOn:"VPC"})}let l=[];for(let p=0;p<i;p++){let m=`NatEIP${p+1}`;l.push(m),e.addResource(m,"AWS::EC2::EIP",{Domain:"vpc",Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-nat-eip-${p+1}`)}]},{dependsOn:"VPCGatewayAttachment"})}let u=[];for(let p=0;p<i;p++){let m=`NatGateway${p+1}`;u.push(m);let g=p%r;e.addResource(m,"AWS::EC2::NatGateway",{AllocationId:d.getAtt(l[p],"AllocationId"),SubnetId:d.ref(o[g]),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-nat-${p+1}`)}]},{dependsOn:[l[p],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((p,m)=>{e.addResource(`PublicSubnetRouteTableAssociation${m+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:d.ref(p),RouteTableId:d.ref("PublicRouteTable")},{dependsOn:[p,"PublicRouteTable"]})}),c.forEach((p,m)=>{let g=`PrivateRouteTable${m+1}`,y=m%i;e.addResource(g,"AWS::EC2::RouteTable",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-private-rt-${m+1}`)}]},{dependsOn:"VPC"}),e.addResource(`PrivateRoute${m+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${m+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:d.ref(p),RouteTableId:d.ref(g)},{dependsOn:[p,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},(p,m)=>d.ref(`PrivateRouteTable${m+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((p)=>d.ref(p))),Export:{Name:d.sub("${AWS::StackName}-PublicSubnets")}},PrivateSubnets:{Description:"Private subnet IDs",Value:d.join(",",c.map((p)=>d.ref(p))),Export:{Name:d.sub("${AWS::StackName}-PrivateSubnets")}}})}function Sr(e,t){for(let[n,r]of Object.entries(t))Oa(e,n,r)}function Oa(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 Ar(e,t){if(t.certificate)$a(e,t.certificate);if(t.waf?.enabled)Ba(e,t.waf);if(t.securityGroups)for(let[n,r]of Object.entries(t.securityGroups))Fa(e,n,r)}function $a(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 Ba(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 Fa(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 Cr(e,t){for(let[n,r]of Object.entries(t)){if(r.type==="efs"){_a(e,n,r);continue}Ga(e,n,r)}}function Ga(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 _a(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 vr{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){br(this,e)}addStorageResources(e){Cr(this,e)}addComputeResources(e){mr(this,e)}addDatabaseResources(e){gr(this,e)}addFunctionResources(e){yr(this,e)}addCacheResources(e){lr(this,e)}addQueueResources(e){Sr(this,e)}addMessagingResources(e){hr(this,e)}addCDNResources(e){ur(this,e)}addApiGatewayResources(e){cr(this,e)}addMonitoringResources(e){fr(this,e)}addSecurityResources(e){Ar(this,e)}}function Ep(e){return new vr(e).build()}function Ip(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 Np(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 kp(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 Lp(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:p="on",region:m="us-east-1"}=e;return{project:{name:t,slug:n,region:m},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:p,domain:i}}}}}function Bp(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 Fp(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 _p(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 Vp(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 Hp(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 Kp(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 zp(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 Jp(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 Zp(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 eg(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
|
|
2489
|
+
| 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 Qa(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 Ir(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 Dr(e,t){for(let[n,r]of Object.entries(t))Ja(e,n,r)}function Ja(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 Nr(e,t){if(t.certificate)Ya(e,t.certificate);if(t.waf?.enabled)Za(e,t.waf);if(t.securityGroups)for(let[n,r]of Object.entries(t.securityGroups))Xa(e,n,r)}function Ya(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 Za(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 Xa(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 xr(e,t){for(let[n,r]of Object.entries(t)){if(r.type==="efs"){to(e,n,r);continue}eo(e,n,r)}}function eo(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 to(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 kr{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){Ir(this,e)}addStorageResources(e){xr(this,e)}addComputeResources(e){vr(this,e)}addDatabaseResources(e){Rr(this,e)}addFunctionResources(e){Pr(this,e)}addCacheResources(e){Sr(this,e)}addQueueResources(e){Dr(this,e)}addMessagingResources(e){Er(this,e)}addCDNResources(e){Ar(this,e)}addApiGatewayResources(e){br(this,e)}addMonitoringResources(e){wr(this,e)}addSecurityResources(e){Nr(this,e)}}function Jp(e){return new kr(e).build()}function Zp(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 eg(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 ng(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 ig(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 og(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 cg(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 ug(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 mg(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 gg(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 hg(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 bg(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 Ag(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 vg(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 Rg(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
|
|
2490
2490
|
# Install Node.js or PHP/Python based on app needs
|
|
2491
2491
|
# Configure application server (PM2, Nginx, Apache)
|
|
2492
2492
|
# Mount EFS for shared file storage
|
|
2493
|
-
`}},storage:{uploads:{type:"efs",performanceMode:"generalPurpose",throughputMode:"bursting",encrypted:!0,lifecyclePolicy:{transitionToIA:30}},backups:{public:!1,versioning:!0,encryption:!0,lifecycleRules:[{id:"ArchiveOldBackups",enabled:!0,transitions:[{days:90,storageClass:"GLACIER"}]}]},static:{public:!0,versioning:!1,encryption:!1,cors:[{allowedOrigins:[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
|
|
2494
|
-
`),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,...
|
|
2495
|
-
`),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
|
|
2496
|
-
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 Qt(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,Qt(a,`${s}.${o+1}`));else n[`${s}.${o+1}`]=String(a)});else if(typeof i==="object"&&i!==null)Object.assign(n,Qt(i,s));else if(i!==void 0&&i!==null)n[s]=String(i)}return n}function uo(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 p=i.indexOf(l,c),m=i.indexOf(u,c);if(m===-1)return-1;if(p!==-1&&p<m){let g=i[p+l.length];if(g===">"||g===" "||g==="/"){let y=i.indexOf(">",p);if(y!==-1&&i[y-1]==="/")c=y+1;else o++,c=y+1}else c=p+l.length}else{if(o--,o===0)return m;c=m+u.length}}return-1}function n(i,s){while(s<i.length&&/\s/.test(i[s]))s++;if(s>=i.length||i[s]!=="<"){let f=i.indexOf("<",s);if(f===-1)return{value:i.slice(s).trim(),end:i.length};return{value:i.slice(s,f).trim(),end:f}}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}>`,p=t(i,o,l);if(p===-1)return{value:void 0,end:s+a[0].length};let m=i.slice(l,p).trim();if(!m.includes("<"))return{value:m,end:p+u.length};let g={},y=l;while(y<p){while(y<p&&/\s/.test(i[y]))y++;if(y>=p)break;if(i[y]!=="<"||i[y+1]==="/")break;let f=i.slice(y).match(/^<(\w+)/);if(!f)break;let S=f[1],v=n(i,y);if(v.value===void 0){y++;continue}if(S==="member"||g[S]!==void 0){if(!Array.isArray(g[S]))g[S]=g[S]!==void 0?[g[S]]:[];g[S].push(v.value)}else g[S]=v.value;y=v.end}return{value:g,end:p+u.length}}return n(e,0).value||{}}function mo(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function po(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 go(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 _e();var yo=5242880,Jt=5242880;var ho=5242880;class Yt{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 st(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 K(`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:Jt});if(i>ho){let a=So(s).stream();return this.uploadMultipart(e,t,a,{...r,partSize:Jt})}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||Vr(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[m,g]of Object.entries(i.metadata))o[`x-amz-meta-${m.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 m=await u.text();throw new K(`Failed to put object: ${m}`,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 K(`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 K(`Failed to delete objects: ${y}`,o.status,e)}let c=await o.text(),l=[],u=[],p=/<Deleted><Key>([^<]+)<\/Key>/g,m;while((m=p.exec(c))!==null)l.push(m[1]);let g=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((m=g.exec(c))!==null)u.push({key:m[1],error:`${m[2]}: ${m[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 K(`Failed to list objects: ${o}`,s.status,e)}let a=await s.text();return fo(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 K(`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 K(`Failed to copy object: ${g}`,l.status,n,r)}let p=(await l.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:p?p[1]:""}}async getPresignedUrl(e,t,n={}){let r=await this.getCredentials(),i=this.buildUrl(e,t);return xr({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||Jt,yo),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||Vr(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[m,g]of Object.entries(n.metadata))a[`x-amz-meta-${m.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 m=await c.text();throw new K(`Failed to initiate multipart upload: ${m}`,c.status,e,t)}let u=(await c.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!u)throw new K("Failed to parse upload ID from response",0,e,t);let p=i;if(c.url)try{let m=new URL(c.url);m.search="",p=m.toString()}catch{}return{uploadId:u[1],baseUrl:p}}async uploadParts(e,t,n,r,i,s,a,o,c,l){let u=[],p=i.getReader(),m=1,g=new Uint8Array(0),y=0,f=o?Math.ceil(o/s):void 0,S=new Map,v=async(A,P)=>{let R=`${n}?partNumber=${P}&uploadId=${encodeURIComponent(r)}`,E={"Content-Length":String(A.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},D=V({method:"PUT",url:R,headers:E,...a,service:"s3",region:this.region}),w=await fetch(D.url,{method:D.method,headers:D.headers,body:A,redirect:"error"});if(!w.ok){let k=await w.text();throw new K(`Failed to upload part ${P}: ${k}`,w.status,e,t)}let N=(w.headers.get("ETag")||"").replace(/"/g,"");if(!N)throw new K(`Missing ETag for part ${P}`,w.status,e,t);return{partNumber:P,etag:N}},T=async()=>{let A=await Promise.race(S.values());S.delete(A.partNumber),u.push(A)};while(!0){let{done:A,value:P}=await p.read();if(P){let R=new Uint8Array(g.length+P.length);R.set(g),R.set(P,g.length),g=R}while(g.length>=s||A&&g.length>0){let R=g.slice(0,s);g=g.slice(s);let E=m++;if(S.size>=c)await T();if(S.set(E,v(R,E)),y+=R.byteLength,l)l({loaded:y,total:o||y,part:E,totalParts:f||E})}if(A)break}while(S.size>0)await T();return u.sort((A,P)=>A.partNumber-P.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 K(`Failed to complete multipart upload: ${y}`,u.status,e,t)}let m=(await u.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:m?m[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 K 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 fo(e){let t=[],n=[],r=/<Contents>([\s\S]*?)<\/Contents>/g,i;while((i=r.exec(e))!==null){let a=i[1];t.push({key:te(a,"Key")||"",lastModified:new Date(te(a,"LastModified")||0),etag:(te(a,"ETag")||"").replace(/"/g,""),size:Number(te(a,"Size")||0),storageClass:te(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:te(e,"IsTruncated")==="true",continuationToken:te(e,"ContinuationToken")||void 0,nextContinuationToken:te(e,"NextContinuationToken")||void 0,keyCount:Number(te(e,"KeyCount")||0),maxKeys:Number(te(e,"MaxKeys")||1000),prefix:te(e,"Prefix")||void 0,delimiter:te(e,"Delimiter")||void 0}}function te(e,t){let n=new RegExp(`<${t}>([^<]*)</${t}>`),r=e.match(n);return r?r[1]:null}function bo(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function Vr(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 So(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function Ao(e){return new Yt(e)}await _e();class Co{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await We(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"?>
|
|
2493
|
+
`}},storage:{uploads:{type:"efs",performanceMode:"generalPurpose",throughputMode:"bursting",encrypted:!0,lifecyclePolicy:{transitionToIA:30}},backups:{public:!1,versioning:!0,encryption:!0,lifecycleRules:[{id:"ArchiveOldBackups",enabled:!0,transitions:[{days:90,storageClass:"GLACIER"}]}]},static:{public:!0,versioning:!1,encryption:!1,cors:[{allowedOrigins:[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 Eg(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 Ig(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 Ng(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 no=_t,ro="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function io(e){let t=e.split(".").filter(Boolean);return t.length<=2?e:t.slice(-2).join(".")}function so(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 ao=20000,oo=12000;function co(e){return ao+so(e)%oo}function Lr(e,t){let n=io(e);if(n===e)return`dashboard.${n}`;for(let r of t)if(r===n)return`dashboard.${n}`;return`dashboard.${e}`}function Or(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 lo(e,t,n){if(n)return n;let r=Or(e,t),i=r[0];if(!i)return null;return Lr(i,r)}function uo(e,t,n){if(n)return[n];let r=Or(e,t),i=[];for(let s of r){let a=Lr(s,r);if(!i.includes(a))i.push(a)}return i}function mo(e){return Object.entries(e.sites??{}).some(([t,n])=>{if(!n)return!1;let r=n.root??"";return po(t)||r==="ui/dist"||r.endsWith("/ui/dist")||r.endsWith("/dist/ui")})}var $r="dashboard-";function Mr(e){return $r+e.replace(/^dashboard\./,"").replace(/\./g,"-")}function po(e){return e==="dashboard"||e.startsWith($r)}function go(e,t,n){if(mo(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=lo(e,t,n.domain);if(!a)return[];let o=n.port??co(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 ${ro} --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:[no],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:Mr(a),site:l}]}return uo(e,t,n.domain).map((a)=>({name:Mr(a),site:{root:n.uiRoot,deploy:"server",type:"static",domain:a,ssl:{provider:"letsencrypt"},...i,...r}}))}function Mg(e,t,n){return go(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 Br(e,t){return Zt(e,t)}function Og(...e){return e.reduce((t,n)=>Zt(t,n),{})}function $g(e,t){return(n)=>{let r=e(n);if(typeof t==="function")return Br(r,t(r,n));return Br(r,t)}}function Ge(e){return{infrastructure:e}}function Bg(e){return Ge({monitoring:e})}function Fg(e){return Ge({security:e})}function Gg(e){return Ge({databases:e})}function _g(e){return Ge({cache:e})}function Wg(e){return Ge({cdn:e})}function Vg(e){return Ge({queues:e})}Ve();import{existsSync as zr,readFileSync as en}from"node:fs";import{homedir as Qr}from"node:os";import{join as Jr}from"node:path";function bo(){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 So(e){let t=e?.profile||process.env.AWS_PROFILE||"default",n=e?.credentialsFile||Jr(Qr(),".aws","credentials");if(!zr(n))return null;try{let r=en(n,"utf-8");return Ao(r,t)}catch{return null}}function Ao(e,t){let n=e.split(`
|
|
2494
|
+
`),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 Co(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 vo(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 To(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=bo();if(t)return t;let n=So(e);if(n)return n;let r=await To(e);if(r)return r;let i=await vo(e);if(i)return i;let s=await Co(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 ny(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 Ro(e){let t=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(t)return t;let n=Jr(Qr(),".aws","config");if(zr(n))try{let r=en(n,"utf-8"),i=e||process.env.AWS_PROFILE||"default",s=i==="default"?"[default]":`[profile ${i}]`,a=r.split(`
|
|
2495
|
+
`),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 Yr(e){let t=e||await ct(),n=Ro();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 Po{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 Eo(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 wo(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 Io(n)}async describeStackEvents(e){let t=await this.request("DescribeStackEvents",{StackName:e});return Do(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}
|
|
2496
|
+
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 Eo(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 f=i.indexOf("<",s);if(f===-1)return{value:i.slice(s).trim(),end:i.length};return{value:i.slice(s,f).trim(),end:f}}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 f=i.slice(y).match(/^<(\w+)/);if(!f)break;let b=f[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 wo(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function Io(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 Do(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 No=5242880,nn=5242880;var xo=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 K(`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>xo){let a=Lo(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||Zr(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 K(`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 K(`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>${Mo(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 K(`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 K(`Failed to list objects: ${o}`,s.status,e)}let a=await s.text();return ko(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 K(`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 K(`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 Wr({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,No),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||Zr(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 K(`Failed to initiate multipart upload: ${p}`,c.status,e,t)}let u=(await c.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!u)throw new K("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,f=o?Math.ceil(o/s):void 0,b=new Map,v=async(A,P)=>{let R=`${n}?partNumber=${P}&uploadId=${encodeURIComponent(r)}`,E={"Content-Length":String(A.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},D=V({method:"PUT",url:R,headers:E,...a,service:"s3",region:this.region}),w=await fetch(D.url,{method:D.method,headers:D.headers,body:A,redirect:"error"});if(!w.ok){let k=await w.text();throw new K(`Failed to upload part ${P}: ${k}`,w.status,e,t)}let N=(w.headers.get("ETag")||"").replace(/"/g,"");if(!N)throw new K(`Missing ETag for part ${P}`,w.status,e,t);return{partNumber:P,etag:N}},T=async()=>{let A=await Promise.race(b.values());b.delete(A.partNumber),u.push(A)};while(!0){let{done:A,value:P}=await m.read();if(P){let R=new Uint8Array(g.length+P.length);R.set(g),R.set(P,g.length),g=R}while(g.length>=s||A&&g.length>0){let R=g.slice(0,s);g=g.slice(s);let E=p++;if(b.size>=c)await T();if(b.set(E,v(R,E)),y+=R.byteLength,l)l({loaded:y,total:o||y,part:E,totalParts:f||E})}if(A)break}while(b.size>0)await T();return u.sort((A,P)=>A.partNumber-P.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 K(`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 K 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 ko(e){let t=[],n=[],r=/<Contents>([\s\S]*?)<\/Contents>/g,i;while((i=r.exec(e))!==null){let a=i[1];t.push({key:te(a,"Key")||"",lastModified:new Date(te(a,"LastModified")||0),etag:(te(a,"ETag")||"").replace(/"/g,""),size:Number(te(a,"Size")||0),storageClass:te(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:te(e,"IsTruncated")==="true",continuationToken:te(e,"ContinuationToken")||void 0,nextContinuationToken:te(e,"NextContinuationToken")||void 0,keyCount:Number(te(e,"KeyCount")||0),maxKeys:Number(te(e,"MaxKeys")||1000),prefix:te(e,"Prefix")||void 0,delimiter:te(e,"Delimiter")||void 0}}function te(e,t){let n=new RegExp(`<${t}>([^<]*)</${t}>`),r=e.match(n);return r?r[1]:null}function Mo(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function Zr(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 Lo(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function Oo(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"?>
|
|
2497
2497
|
<InvalidationBatch>
|
|
2498
2498
|
<Paths>
|
|
2499
2499
|
<Quantity>${e.paths.length}</Quantity>
|
|
@@ -2502,24 +2502,24 @@ Reason: ${o.StackStatusReason||"Unknown"}`);await new Promise((c)=>setTimeout(c,
|
|
|
2502
2502
|
</Items>
|
|
2503
2503
|
</Paths>
|
|
2504
2504
|
<CallerReference>${n}</CallerReference>
|
|
2505
|
-
</InvalidationBatch>`,i=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e.distributionId}/invalidation`,s=await
|
|
2505
|
+
</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 he 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,he)}toString(){let e=`${this.name} [${this.code}]: ${this.message}`;if(this.solution)e+=`
|
|
2506
2506
|
|
|
2507
2507
|
\uD83D\uDCA1 Solution: ${this.solution}`;if(this.details&&Object.keys(this.details).length>0){e+=`
|
|
2508
2508
|
|
|
2509
2509
|
Details:`;for(let[t,n]of Object.entries(this.details))e+=`
|
|
2510
|
-
${t}: ${JSON.stringify(n)}`}return e}}class
|
|
2510
|
+
${t}: ${JSON.stringify(n)}`}return e}}class It extends he{constructor(e,t,n){super(e,"CONFIG_ERROR",t,n);this.name="ConfigurationError"}}class ve extends he{constructor(e,t,n){super(e,"CREDENTIAL_ERROR",t,n);this.name="CredentialError"}}class Bo extends he{constructor(e,t,n){super(e,"DEPLOYMENT_ERROR",t,n);this.name="DeploymentError"}}class ei extends he{constructor(e,t,n){super(e,"VALIDATION_ERROR",t,n);this.name="ValidationError"}}class Fo extends he{statusCode;constructor(e,t,n,r){super(e,"AWS_API_ERROR",n,r);this.statusCode=t;this.name="AWSAPIError"}}var Go={NO_CREDENTIALS:{message:"AWS credentials not found",solution:`Configure AWS credentials using one of these methods:
|
|
2511
2511
|
1. Set environment variables: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
|
|
2512
2512
|
2. Create ~/.aws/credentials file with your credentials
|
|
2513
2513
|
3. Use an IAM role (for EC2 instances)
|
|
2514
|
-
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
|
|
2515
|
-
Stack trace:`),console.error(t.stack)}}static success(e){console.log(`✔ ${e}`)}}function
|
|
2514
|
+
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 _o(e){return Go[e]}function Xr(e,t){let n=_o(e);return new he(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 he)console.error(t.toString());else console.error(t.message);if(this.debugMode&&t.stack)console.error(`
|
|
2515
|
+
Stack trace:`),console.error(t.stack)}}static success(e){console.log(`✔ ${e}`)}}function py(e){if(!e)throw Xr("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 ei("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 Xr("INVALID_REGION",{region:e.project.region})}q.success("Configuration validation passed")}function gy(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 by(e="default"){try{q.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");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 Yr(t),q.verbose("Credentials are valid"),q.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 Sy(e,t){return{allowed:t,denied:[]}}function Wo(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 Ay(e){let t=Wo(e);return JSON.stringify({Version:"2012-10-17",Statement:[{Effect:"Allow",Action:t,Resource:"*"}]},null,2)}var X={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 Ty(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:X.ec2["Running On-Demand Instances"],percentage:r/X.ec2["Running On-Demand Instances"]*100,warning:r>X.ec2["Running On-Demand Instances"]*0.8})}if(e.infrastructure?.network?.vpc)t.push({service:"EC2",quotaName:"VPCs",currentValue:1,limit:X.ec2.VPCs,percentage:1/X.ec2.VPCs*100,warning:!1});if(e.infrastructure?.database?.postgres||e.infrastructure?.database?.mysql)t.push({service:"RDS",quotaName:"DB Instances",currentValue:1,limit:X.rds["DB Instances"],percentage:1/X.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:X.s3.Buckets,percentage:r/X.s3.Buckets*100,warning:r>X.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:X.dynamodb.Tables,percentage:r/X.dynamodb.Tables*100,warning:r>X.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 Ry(e){if(e.length===0)return"No quotas to check";let t=`Service Quota Usage:
|
|
2516
2516
|
|
|
2517
2517
|
`,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}:
|
|
2518
2518
|
`;for(let s of i){let a=s.warning?"⚠":"✓";t+=` ${a} ${s.quotaName}: ${s.currentValue}/${s.limit} (${s.percentage.toFixed(1)}%)
|
|
2519
2519
|
`}t+=`
|
|
2520
|
-
`}return t}function
|
|
2521
|
-
`);return
|
|
2522
|
-
`)}function wy(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=Bo(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 Bo(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 Iy(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 Dy(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 Ny(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 Go={$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 Ly(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 Yr={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 sn(){return Yr}function $y(){return Yr.enabled}function By(e){let t=sn();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 Fy(){let e=sn();return{accessKeyId:e.awsAccessKeyId,secretAccessKey:e.awsSecretAccessKey,region:e.awsRegion}}function Gy(){let e=sn();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 Zr{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 Xr{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 ei{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 Wy(e){return{cloudformation:new Zr,s3:new Xr,dynamodb:new ei}}class an{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,p=new Date(u.getTime()+i*60*60*1000),m={id:o,name:c,branch:t,pr:n,commitSha:r,createdAt:u,expiresAt:p,status:"creating",stackName:l,region:a,resources:[]};this.environments.set(o,m);try{let g=this.createPreviewConfig(s,c);return m.status="active",m.url=`https://${c}.preview.example.com`,m}catch(g){throw m.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(p){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 _o=new an;function Wo(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}
|
|
2520
|
+
`}return t}function Py(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 ri}from"node:crypto";import{existsSync as Dt,mkdirSync as Vo,readdirSync as ti,readFileSync as ni,unlinkSync as lt,writeFileSync as Uo}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))Vo(this.cacheDir,{recursive:!0})}getCachePath(e){let t=ri("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=ni(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};Uo(r,JSON.stringify(i),"utf-8")}has(e){return this.get(e)!==void 0}clear(){if(!Dt(this.cacheDir))return;let e=ti(this.cacheDir);for(let t of e)lt(sn(this.cacheDir,t))}prune(){if(!Dt(this.cacheDir))return;let e=ti(this.cacheDir),t=Date.now();for(let n of e){let r=sn(this.cacheDir,n);try{let i=ni(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 ri("sha256").update(e).digest("hex")}clear(){this.cache.clear()}prune(){this.cache.prune()}}var an=null;function Ho(){if(!an)an=new cn;return an}import{createHash as ln}from"node:crypto";import{createReadStream as jo,readdirSync as Ko,statSync as Nt}from"node:fs";import{join as qo,relative as zo}from"node:path";async function ii(e,t={}){let n=t.algorithm||"sha256",r=t.chunkSize||65536;return new Promise((i,s)=>{let a=ln(n),o=jo(e,{highWaterMark:r});o.on("data",(c)=>a.update(c)),o.on("end",()=>i(a.digest("hex"))),o.on("error",s)})}function si(e,t="sha256"){return ln(t).update(e).digest("hex")}function $y(e,t="sha256"){return ln(t).update(e).digest("hex")}async function By(e,t={}){let n=t.ignorePatterns||["node_modules",".git","dist","build",$e()],r=[];async function i(s){let a=Ko(s,{withFileTypes:!0});for(let o of a){let c=qo(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 ii(c,t);r.push({path:l,hash:m,size:u.size,mtime:u.mtimeMs})}}}return await i(e),r}function Fy(e){let n=[...e].sort((r,i)=>r.path.localeCompare(i.path)).map((r)=>`${r.path}:${r.hash}`).join(`
|
|
2521
|
+
`);return si(n)}function Gy(e){let t=Nt(e);return si(`${e}:${t.size}:${t.mtimeMs}`)}function _y(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 Qo{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 ii(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 f=y instanceof Error?y:Error(String(y));if(s.push(f),r)throw o.length=0,f}}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 Vy(e,t,n={}){let r=e.map((i)=>()=>t(i));return un(r,n)}async function Uy(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 Hy(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 ai(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 ai(e){return new Promise((t)=>setTimeout(t,e))}async function Ky(e,t,n="Operation timed out"){return Promise.race([e(),new Promise((r,i)=>setTimeout(()=>i(Error(n)),t))])}class Jo{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 ai(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 Yo(e,t){let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}async function qy(e,t,n){let r=Yo(e,t),i=[];for(let s of r){let a=await n(s);i.push(...a)}return i}function Qy(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 Jy(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(`
|
|
2522
|
+
`)}function Yy(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=Zo(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 Zo(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 Zy(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 Xy(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 eh(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 ec={$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 ih(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 oi={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 oi}function ah(){return oi.enabled}function oh(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 ch(){let e=dn();return{accessKeyId:e.awsAccessKeyId,secretAccessKey:e.awsSecretAccessKey,region:e.awsRegion}}function lh(){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 ci{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 li{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 ui{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 dh(e){return{cloudformation:new ci,s3:new li,dynamodb:new ui}}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 tc=new mn;function nc(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}
|
|
2523
2523
|
|
|
2524
2524
|
on:
|
|
2525
2525
|
${n}:
|
|
@@ -2653,7 +2653,7 @@ jobs:
|
|
|
2653
2653
|
run: |
|
|
2654
2654
|
# Clean up environments older than TTL
|
|
2655
2655
|
bun run cloud env:cleanup --max-age=\${{ env.TTL_HOURS }}
|
|
2656
|
-
`}function
|
|
2656
|
+
`}function rc(e={}){let{schedule:t="0 0 * * *",maxAge:n=48,keepCount:r=10}=e;return`name: Cleanup Stale Preview Environments
|
|
2657
2657
|
|
|
2658
2658
|
on:
|
|
2659
2659
|
schedule:
|
|
@@ -2698,7 +2698,7 @@ jobs:
|
|
|
2698
2698
|
- name: Report cleanup results
|
|
2699
2699
|
run: |
|
|
2700
2700
|
bun run cloud env:list --status=destroyed
|
|
2701
|
-
`}function
|
|
2701
|
+
`}function ic(e={}){let{schedule:t="0 8 * * 1",webhookUrl:n}=e;return`name: Preview Environment Cost Report
|
|
2702
2702
|
|
|
2703
2703
|
on:
|
|
2704
2704
|
schedule:
|
|
@@ -2747,15 +2747,15 @@ jobs:
|
|
|
2747
2747
|
curl -X POST -H 'Content-type: application/json' \\
|
|
2748
2748
|
--data '{"text":"Preview Environment Cost Report\\n\${{ steps.cost.outputs.cost_json }}"}' \\
|
|
2749
2749
|
$SLACK_WEBHOOK_URL`:'run: |\n echo "${{ steps.cost.outputs.cost_json }}"'}
|
|
2750
|
-
`}class
|
|
2751
|
-
`)}function
|
|
2752
|
-
`)}function
|
|
2753
|
-
`)}function
|
|
2754
|
-
`)}class
|
|
2750
|
+
`}class pn{channels=[];addChannel(e){this.channels.push(e)}removeChannel(e){this.channels=this.channels.filter((t)=>t.type!==e)}async notify(e){let t=this.channels.map((n)=>this.sendToChannel(n,e));await Promise.allSettled(t)}async sendToChannel(e,t){switch(e.type){case"slack":await this.sendToSlack(e.config,t);break;case"discord":await this.sendToDiscord(e.config,t);break;case"email":await this.sendToEmail(e.config,t);break;case"webhook":await this.sendToWebhook(e.config,t);break}}async sendToSlack(e,t){let n=this.formatSlackMessage(t,e),r=await fetch(e.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});if(!r.ok)throw Error(`Failed to send Slack notification: ${r.statusText}`)}formatSlackMessage(e,t){let{environment:n,type:r}=e,i={created:":rocket:",updated:":arrows_counterclockwise:",destroyed:":wastebasket:",failed:":x:",expired:":hourglass_flowing_sand:"}[r],s={created:"#36a64f",updated:"#2196F3",destroyed:"#808080",failed:"#f44336",expired:"#ff9800"}[r],a={created:"Preview Environment Created",updated:"Preview Environment Updated",destroyed:"Preview Environment Destroyed",failed:"Preview Environment Failed",expired:"Preview Environment Expired"}[r];return{username:t.username||"ts-cloud",icon_emoji:t.iconEmoji||":cloud:",channel:t.channel,attachments:[{color:s,title:`${i} ${a}`,fields:[{title:"Environment",value:n.name,short:!0},{title:"Branch",value:n.branch,short:!0},...n.pr?[{title:"PR",value:`#${n.pr}`,short:!0}]:[],{title:"Commit",value:n.commitSha.substring(0,7),short:!0},...n.url?[{title:"URL",value:n.url,short:!1}]:[],...r==="created"?[{title:"Expires",value:n.expiresAt.toLocaleString(),short:!0}]:[]],footer:"ts-cloud Preview Environments",ts:Math.floor(e.timestamp.getTime()/1000)}]}}async sendToDiscord(e,t){let n=this.formatDiscordMessage(t,e),r=await fetch(e.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});if(!r.ok)throw Error(`Failed to send Discord notification: ${r.statusText}`)}formatDiscordMessage(e,t){let{environment:n,type:r}=e,i={created:":rocket:",updated:":arrows_counterclockwise:",destroyed:":wastebasket:",failed:":x:",expired:":hourglass:"}[r],s={created:3581519,updated:2201331,destroyed:8421504,failed:16007990,expired:16750592}[r],a={created:"Preview Environment Created",updated:"Preview Environment Updated",destroyed:"Preview Environment Destroyed",failed:"Preview Environment Failed",expired:"Preview Environment Expired"}[r];return{username:t.username||"ts-cloud",avatar_url:t.avatarUrl,embeds:[{title:`${i} ${a}`,color:s,fields:[{name:"Environment",value:n.name,inline:!0},{name:"Branch",value:n.branch,inline:!0},...n.pr?[{name:"PR",value:`#${n.pr}`,inline:!0}]:[],{name:"Commit",value:`\`${n.commitSha.substring(0,7)}\``,inline:!0},...n.url?[{name:"URL",value:n.url,inline:!1}]:[]],timestamp:e.timestamp.toISOString(),footer:{text:"ts-cloud Preview Environments"}}]}}async sendToEmail(e,t){console.log(`Email notification would be sent to ${e.to.join(", ")}`)}async sendToWebhook(e,t){let n=await fetch(e.url,{method:e.method||"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify({event:t.type,environment:t.environment,timestamp:t.timestamp.toISOString(),metadata:t.metadata})});if(!n.ok)throw Error(`Failed to send webhook notification: ${n.statusText}`)}}var sc=new pn;function Ah(e){let{columns:t,data:n,border:r=!0,header:i=!0,compact:s=!1,maxWidth:a}=e;if(n.length===0)return"No data to display";let o=t.map((l)=>{let u=l.label.length,m=Math.max(...n.map((g)=>(l.formatter?l.formatter(g[l.key]):String(g[l.key]||"")).length)),p=l.width||Math.max(u,m);if(a&&p>a)p=a;return p}),c=[];if(r)c.push(gn(o,"top",s));if(i){if(c.push(di(t.map((l)=>l.label),o,t.map((l)=>l.align||"left"),r)),r)c.push(gn(o,"middle",s))}for(let l of n){let u=t.map((m)=>{let p=m.formatter?m.formatter(l[m.key]):String(l[m.key]||"");return oc(p,o[t.indexOf(m)])});c.push(di(u,o,t.map((m)=>m.align||"left"),r))}if(r)c.push(gn(o,"bottom",s));return c.join(`
|
|
2751
|
+
`)}function di(e,t,n,r){let i=e.map((s,a)=>{let o=t[a],c=n[a];return ac(s,o,c)});if(r)return`│ ${i.join(" │ ")} │`;return i.join(" ")}function gn(e,t,n){let r=t==="top"?"┌":t==="middle"?"├":"└",i=t==="top"?"┐":t==="middle"?"┤":"┘",s=t==="top"?"┬":t==="middle"?"┼":"┴",a="─";if(n)return r+e.map((o)=>"─".repeat(o+2)).join(s)+i;return r+e.map((o)=>"─".repeat(o+2)).join(s)+i}function ac(e,t,n){let r=mi(e).length;if(r>=t)return e;let i=t-r;switch(n){case"right":return" ".repeat(i)+e;case"center":{let s=Math.floor(i/2),a=i-s;return" ".repeat(s)+e+" ".repeat(a)}default:return e+" ".repeat(i)}}function oc(e,t){if(mi(e).length<=t)return e;return e.substring(0,t-1)+"…"}function mi(e){return e.replace(/\x1B\[[0-9;]*m/g,"")}function Ch(e,t={}){let{indent:n=" ",showMetadata:r=!1}=t,i=[];function s(a,o,c){let u=o+(c?"└─ ":"├─ ")+a.label;if(i.push(u),r&&a.metadata){let m=o+(c?" ":"│ ");for(let[p,g]of Object.entries(a.metadata))i.push(`${m}${p}: ${g}`)}if(a.children&&a.children.length>0){let m=o+(c?" ":"│ ");a.children.forEach((p,g)=>{s(p,m,g===a.children.length-1)})}}return e.forEach((a,o)=>{s(a,"",o===e.length-1)}),i.join(`
|
|
2752
|
+
`)}function vh(e){let{total:t,current:n,width:r=40,format:i=":bar :percent :current/:total",complete:s="█",incomplete:a="░"}=e,o=Math.min(100,Math.max(0,n/t*100)),c=Math.floor(r*n/t),l=r-c,u=s.repeat(c)+a.repeat(l);return i.replace(":bar",u).replace(":percent",`${o.toFixed(0)}%`).replace(":current",String(n)).replace(":total",String(t))}function Th(e,t=2){if(e===0)return"0 Bytes";let n=1024,r=t<0?0:t,i=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],s=Math.floor(Math.log(e)/Math.log(n));return`${Number.parseFloat((e/Math.pow(n,s)).toFixed(r))} ${i[s]}`}function Rh(e){if(e<1000)return`${e}ms`;let t=Math.floor(e/1000);if(t<60)return`${t}s`;let n=Math.floor(t/60),r=t%60;if(n<60)return r>0?`${n}m ${r}s`:`${n}m`;let i=Math.floor(n/60),s=n%60;if(i<24)return s>0?`${i}h ${s}m`:`${i}h`;let a=Math.floor(i/24),o=i%24;return o>0?`${a}d ${o}h`:`${a}d`}function Ph(e,t="•"){return e.map((n)=>`${t} ${n}`).join(`
|
|
2753
|
+
`)}function Eh(e,t={}){let{indent:n="",separator:r=": "}=t,i=Math.max(...Object.keys(e).map((s)=>s.length));return Object.entries(e).map(([s,a])=>{let o=s.padEnd(i);return`${n}${o}${r}${a}`}).join(`
|
|
2754
|
+
`)}class cc{total;current=0;width;format;message;showETA;showPercentage;showCounter;startTime=Date.now();lastUpdate=0;constructor(e){this.total=e.total,this.current=e.current||0,this.width=e.width||40,this.format=e.format||":message :bar :percent :eta",this.message=e.message||"Progress",this.showETA=e.showETA!==!1,this.showPercentage=e.showPercentage!==!1,this.showCounter=e.showCounter!==!1}tick(e=1){this.current=Math.min(this.total,this.current+e),this.lastUpdate=Date.now()}update(e){this.current=Math.min(this.total,Math.max(0,e)),this.lastUpdate=Date.now()}setMessage(e){this.message=e}getPercentage(){return Math.min(100,this.current/this.total*100)}getETA(){if(this.current===0)return 0;let e=Date.now()-this.startTime,t=this.current/e,n=this.total-this.current;return Math.round(n/t)}getETAFormatted(){if(this.current===0)return"calculating...";if(this.current===this.total)return"complete";let e=this.getETA();if(e<1000)return"< 1s";if(e<60000)return`${Math.round(e/1000)}s`;let t=Math.floor(e/60000);if(t<60)return`${t}m`;let n=Math.floor(t/60),r=t%60;if(n<24)return r>0?`${n}h ${r}m`:`${n}h`;let i=Math.floor(n/24),s=n%24;return s>0?`${i}d ${s}h`:`${i}d`}render(){let e=this.getPercentage(),t=Math.floor(this.width*this.current/this.total),n=this.width-t,r="█".repeat(t)+"░".repeat(n),i=`${e.toFixed(1)}%`,s=`${this.current}/${this.total}`,a=this.showETA?`ETA: ${this.getETAFormatted()}`:"",o=this.format.replace(":message",this.message).replace(":bar",r).replace(":percent",this.showPercentage?i:"").replace(":counter",this.showCounter?s:"").replace(":eta",a).replace(":current",String(this.current)).replace(":total",String(this.total));return o=o.replace(/\s+/g," ").trim(),o}isComplete(){return this.current>=this.total}}class lc{steps;currentStepIndex=0;constructor(e){this.steps=e.map((t)=>({name:t,status:"pending"}))}startStep(e,t){if(e>=0&&e<this.steps.length)this.steps[e].status="active",this.steps[e].message=t,this.currentStepIndex=e}completeStep(e){if(this.currentStepIndex>=0&&this.currentStepIndex<this.steps.length)this.steps[this.currentStepIndex].status="completed",this.steps[this.currentStepIndex].message=e,this.currentStepIndex++}failStep(e){if(this.currentStepIndex>=0&&this.currentStepIndex<this.steps.length)this.steps[this.currentStepIndex].status="failed",this.steps[this.currentStepIndex].error=e}skipStep(e){if(this.currentStepIndex>=0&&this.currentStepIndex<this.steps.length)this.steps[this.currentStepIndex].status="skipped",this.steps[this.currentStepIndex].message=e,this.currentStepIndex++}getStep(e){return this.steps[e]}getSteps(){return this.steps}render(){let e=[];for(let t of this.steps){let r=`${this.getStatusIcon(t.status)} ${t.name}`;if(t.message)r+=` - ${t.message}`;if(t.error)r+=`
|
|
2755
2755
|
Error: ${t.error}`;e.push(r)}return e.join(`
|
|
2756
|
-
`)}getStatusIcon(e){switch(e){case"pending":return"○";case"active":return"◐";case"completed":return"✓";case"failed":return"✗";case"skipped":return"⊘";default:return"○"}}isComplete(){return this.steps.every((e)=>e.status==="completed"||e.status==="skipped")}hasFailed(){return this.steps.some((e)=>e.status==="failed")}}class
|
|
2756
|
+
`)}getStatusIcon(e){switch(e){case"pending":return"○";case"active":return"◐";case"completed":return"✓";case"failed":return"✗";case"skipped":return"⊘";default:return"○"}}isComplete(){return this.steps.every((e)=>e.status==="completed"||e.status==="skipped")}hasFailed(){return this.steps.some((e)=>e.status==="failed")}}class uc{frames=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];currentFrame=0;message;interval=null;constructor(e="Loading..."){this.message=e}start(){if(this.interval)return;this.interval=setInterval(()=>{this.currentFrame=(this.currentFrame+1)%this.frames.length},80)}stop(){if(this.interval)clearInterval(this.interval),this.interval=null}setMessage(e){this.message=e}render(){return`${this.frames[this.currentFrame]} ${this.message}`}succeed(e){return this.stop(),`✓ ${e||this.message}`}fail(e){return this.stop(),`✗ ${e||this.message}`}warn(e){return this.stop(),`⚠ ${e||this.message}`}info(e){return this.stop(),`ℹ ${e||this.message}`}}class dc{tasks=[];add(e){return this.tasks.push({title:e,status:"pending"}),this.tasks.length-1}start(e){if(e>=0&&e<this.tasks.length)this.tasks[e].status="running"}complete(e,t){if(e>=0&&e<this.tasks.length)this.tasks[e].status="completed",this.tasks[e].output=t}fail(e,t){if(e>=0&&e<this.tasks.length)this.tasks[e].status="failed",this.tasks[e].output=t}render(){let e=[];for(let t of this.tasks){let r=`${this.getStatusIcon(t.status)} ${t.title}`;if(t.output)r+=`
|
|
2757
2757
|
${t.output}`;e.push(r)}return e.join(`
|
|
2758
|
-
`)}getStatusIcon(e){switch(e){case"pending":return"○";case"running":return"◐";case"completed":return"✓";case"failed":return"✗";default:return"○"}}}function
|
|
2758
|
+
`)}getStatusIcon(e){switch(e){case"pending":return"○";case"running":return"◐";case"completed":return"✓";case"failed":return"✗";default:return"○"}}}function mc(e,t){let n=[];for(let r=0;r<=t.length;r++)n[r]=[r];for(let r=0;r<=e.length;r++)n[0][r]=r;for(let r=1;r<=t.length;r++)for(let i=1;i<=e.length;i++)if(t.charAt(r-1)===e.charAt(i-1))n[r][i]=n[r-1][i-1];else n[r][i]=Math.min(n[r-1][i-1]+1,n[r][i-1]+1,n[r-1][i]+1);return n[t.length][e.length]}function pc(e,t){let n=mc(e.toLowerCase(),t.toLowerCase()),r=Math.max(e.length,t.length);if(r===0)return 1;return 1-n/r}function pi(e,t,n=0.5){return t.map((i)=>({command:i,score:pc(e,i)})).filter((i)=>i.score>=n).sort((i,s)=>s.score-i.score).map((i)=>i.command).slice(0,5)}function Dh(e,t){if(t.length===0)return`Unknown command: '${e}'
|
|
2759
2759
|
|
|
2760
2760
|
Run 'ts-cloud --help' to see available commands.`;if(t.length===1)return`Unknown command: '${e}'
|
|
2761
2761
|
|
|
@@ -2763,22 +2763,22 @@ Did you mean: ${t[0]}?`;return`Unknown command: '${e}'
|
|
|
2763
2763
|
|
|
2764
2764
|
Did you mean one of these?
|
|
2765
2765
|
${t.map((n)=>` • ${n}`).join(`
|
|
2766
|
-
`)}`}function
|
|
2767
|
-
`)}function
|
|
2768
|
-
`)}function
|
|
2769
|
-
`)}function
|
|
2766
|
+
`)}`}function Nh(e,t){return pi(e,t,0.7).length>0}function xh(e,t){let n=t.find((s)=>s.commands.some((a)=>a.name===e||a.aliases?.includes(e)));if(!n)return"No contextual help available.";let r=[];r.push(`${n.name}`),r.push("─".repeat(n.name.length)),r.push(n.description),r.push(""),r.push("Related commands:");for(let s of n.commands)if(r.push(` ${s.name.padEnd(20)} ${s.description}`),s.aliases&&s.aliases.length>0)r.push(` Aliases: ${s.aliases.join(", ")}`);let i=n.commands.find((s)=>s.name===e||s.aliases?.includes(e));if(i?.examples&&i.examples.length>0){r.push(""),r.push("Examples:");for(let s of i.examples)r.push(` ${s}`)}return r.join(`
|
|
2767
|
+
`)}function kh(e,t){let n=[],r=e.toLowerCase();for(let i of t)for(let s of i.commands){let a=s.name.toLowerCase().includes(r),o=s.description.toLowerCase().includes(r),c=s.aliases?.some((l)=>l.toLowerCase().includes(r));if(a||o||c)n.push({command:s,category:i.name})}return n}function Mh(e,t,n=10){let r=e.toLowerCase(),i=t.filter((a)=>a.toLowerCase().startsWith(r)),s=t.filter((a)=>a.toLowerCase().includes(r)&&!a.toLowerCase().startsWith(r));return[...i,...s].slice(0,n)}function Lh(e,t){let n=e.toLowerCase();return t.filter((r)=>{let i=r.name.toLowerCase().includes(n),s=r.alias?.toLowerCase().includes(n);return i||s})}function Oh(e){if(e.length===0)return"No matching flags found.";let t=[];for(let n of e){let r=` --${n.name}`;if(n.alias)r+=`, -${n.alias}`;if(r=r.padEnd(30),r+=n.description,n.required)r+=" (required)";t.push(r)}return t.join(`
|
|
2768
|
+
`)}function $h(e){let t=[];if(t.push(`Usage: ts-cloud ${e.name}`),t.push(""),t.push(e.description),e.aliases&&e.aliases.length>0)t.push(""),t.push(`Aliases: ${e.aliases.join(", ")}`);if(e.examples&&e.examples.length>0){t.push(""),t.push("Examples:");for(let n of e.examples)t.push(` ${n}`)}return t.join(`
|
|
2769
|
+
`)}function Bh(e,t,n=[]){let r={valid:!0,errors:[],warnings:[],suggestions:[]},[i,...s]=e.split(" ");if(!t.includes(i)){r.valid=!1,r.errors.push(`Unknown command: ${i}`);let a=pi(i,t);if(a.length>0)r.suggestions.push(...a)}for(let a of n)if(!s.some((o)=>o===`--${a}`||o.startsWith(`--${a}=`)))r.valid=!1,r.errors.push(`Missing required flag: --${a}`);return r}class gc{options;running=!1;history={commands:[],maxSize:1000};historyIndex=-1;constructor(e){this.options={prompt:e.prompt||"> ",welcome:e.welcome||'Welcome to ts-cloud interactive mode. Type "help" for available commands.',...e}}async start(){if(this.running=!0,this.options.welcome)console.log(this.options.welcome),console.log("");if(this.options.historyFile)await this.loadHistory();while(this.running)try{let e=await this.readInput();if(!e.trim())continue;this.addToHistory(e),await this.executeCommand(e)}catch(e){if(e instanceof Error)console.error(`Error: ${e.message}`)}if(this.options.historyFile)await this.saveHistory()}stop(){this.running=!1}async readInput(){return new Promise((e)=>{process.stdout.write(this.options.prompt||"> "),e("")})}async executeCommand(e){let[t,...n]=this.parseCommand(e);if(t==="exit"||t==="quit"){this.stop();return}if(t==="help"){this.showHelp();return}if(t==="history"){this.showHistory();return}if(t==="clear"){console.clear();return}let r=this.findCommand(t);if(!r){console.error(`Unknown command: ${t}`),console.log('Type "help" to see available commands.');return}try{await r.handler(n)}catch(i){if(i instanceof Error)console.error(`Command failed: ${i.message}`)}}parseCommand(e){return e.trim().split(/\s+/)}findCommand(e){for(let[t,n]of this.options.commands)if(n.name===e||n.aliases?.includes(e))return n;return}showHelp(){console.log("Available commands:"),console.log("");let e=Array.from(this.options.commands.values());console.log(" help Show this help message"),console.log(" history Show command history"),console.log(" clear Clear screen"),console.log(" exit, quit Exit interactive mode"),console.log("");for(let t of e){let n=` ${t.name.padEnd(20)} ${t.description}`;if(t.aliases&&t.aliases.length>0)n+=` (aliases: ${t.aliases.join(", ")})`;console.log(n)}}showHistory(){if(this.history.commands.length===0){console.log("No command history");return}console.log("Command history:"),this.history.commands.forEach((e,t)=>{console.log(` ${(t+1).toString().padStart(4)} ${e}`)})}addToHistory(e){if(this.history.commands[this.history.commands.length-1]===e)return;if(this.history.commands.push(e),this.history.commands.length>this.history.maxSize)this.history.commands=this.history.commands.slice(-this.history.maxSize);this.historyIndex=this.history.commands.length}historyBack(){if(this.historyIndex>0)return this.historyIndex--,this.history.commands[this.historyIndex];return}historyForward(){if(this.historyIndex<this.history.commands.length-1)return this.historyIndex++,this.history.commands[this.historyIndex];return this.historyIndex=this.history.commands.length,""}autocomplete(e){let t=[],n=["help","history","clear","exit","quit"];for(let r of n)if(r.startsWith(e))t.push(r);for(let[r,i]of this.options.commands){if(i.name.startsWith(e))t.push(i.name);if(i.aliases){for(let s of i.aliases)if(s.startsWith(e))t.push(s)}}return t}async loadHistory(){if(!this.options.historyFile)return;try{let e=await import("node:fs/promises"),t=await e.readFile(this.options.historyFile,"utf-8");this.history.commands=t.split(`
|
|
2770
2770
|
`).filter((n)=>n.trim()),this.historyIndex=this.history.commands.length}catch{}}async saveHistory(){if(!this.options.historyFile)return;try{let e=await import("node:fs/promises");await e.writeFile(this.options.historyFile,this.history.commands.join(`
|
|
2771
|
-
`))}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
|
|
2772
|
-
`)}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
|
|
2773
|
-
`)}function
|
|
2774
|
-
`)}class ii{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 Ph=new ii;class si{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 ai{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 oi{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 ci{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 wh=new si,Ih=new ai,Dh=new oi,Nh=new ci;var ce=[{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 ot(e){return ce.find((t)=>t.code===e)}function kh(){return ce}function Mh(e){let t=e.toLowerCase();return ce.filter((n)=>n.location.toLowerCase().includes(t))}function Lh(e){return ce.filter((t)=>t.compliance.includes(e))}function Oh(e){return ce.filter((t)=>t.pricing.tier===e)}function $h(e){return ce.some((t)=>t.code===e)}function Bh(e){if(e.continent==="North America")return ot("us-east-1");if(e.continent==="Europe")return ot("eu-west-1");if(e.continent==="Asia")return ot("ap-southeast-1");return ot("us-east-1")}function Fh(e){let t=[...ce];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 Gh(e){let t=ot(e);if(!t)throw Error(`Invalid region: ${e}`);let n=[];for(let r of ce){if(r.code===e)continue;let i=rc(t,r),s=ic(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 rc(e,t){let n={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},r=ct(e.location),i=ct(t.location);return Math.abs((n[r]||0)-(n[i]||0))}function ic(e,t){return ct(e.location)===ct(t.location)}function ct(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 sc(e){return`${e.name} (${e.code})`}function _h(e){return e.map((t)=>sc(t)).join(`
|
|
2775
|
-
`)}function Wh(){let e={total:ce.length,byContinent:{},byPricingTier:{}};for(let t of ce){let n=ct(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 li{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 ui{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 qh=new li,zh=new ui;var ac={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"}]}},Jh={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"]}}}]}}},Yh={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 Zh(e){return ac[e]}function Xh(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 ef(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 tf(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(`
|
|
2776
|
-
`)}function
|
|
2771
|
+
`))}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 yc{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 hc{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 fc{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(`
|
|
2772
|
+
`)}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 _h(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(`
|
|
2773
|
+
`)}function Wh(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(`
|
|
2774
|
+
`)}class gi{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 Qh=new gi;class yi{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 fi{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 bi{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 Yh=new yi,Zh=new hi,Xh=new fi,ef=new bi;var ce=[{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 ce.find((t)=>t.code===e)}function nf(){return ce}function rf(e){let t=e.toLowerCase();return ce.filter((n)=>n.location.toLowerCase().includes(t))}function sf(e){return ce.filter((t)=>t.compliance.includes(e))}function af(e){return ce.filter((t)=>t.pricing.tier===e)}function of(e){return ce.some((t)=>t.code===e)}function cf(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 lf(e){let t=[...ce];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 uf(e){let t=ut(e);if(!t)throw Error(`Invalid region: ${e}`);let n=[];for(let r of ce){if(r.code===e)continue;let i=bc(t,r),s=Sc(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 bc(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 Sc(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 Ac(e){return`${e.name} (${e.code})`}function df(e){return e.map((t)=>Ac(t)).join(`
|
|
2775
|
+
`)}function mf(){let e={total:ce.length,byContinent:{},byPricingTier:{}};for(let t of ce){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 Si{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 Ai{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 bf=new Si,Sf=new Ai;var Cc={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"}]}},Cf={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"]}}}]}}},vf={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 Tf(e){return Cc[e]}function Rf(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 Pf(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 Ef(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(`
|
|
2776
|
+
`)}function xf(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}
|
|
2777
2777
|
|
|
2778
2778
|
on:
|
|
2779
2779
|
${n}:
|
|
2780
2780
|
branches:
|
|
2781
|
-
${r.map((
|
|
2781
|
+
${r.map((p)=>` - ${p}`).join(`
|
|
2782
2782
|
`)}
|
|
2783
2783
|
|
|
2784
2784
|
env:
|
|
@@ -2826,7 +2826,7 @@ jobs:
|
|
|
2826
2826
|
- name: Install dependencies
|
|
2827
2827
|
run: bun install
|
|
2828
2828
|
|
|
2829
|
-
${
|
|
2829
|
+
${m?`- name: Configure AWS credentials (OIDC)
|
|
2830
2830
|
uses: aws-actions/configure-aws-credentials@v4
|
|
2831
2831
|
with:
|
|
2832
2832
|
role-to-assume: ${a}
|
|
@@ -2842,7 +2842,7 @@ jobs:
|
|
|
2842
2842
|
|
|
2843
2843
|
- name: Post-deployment tests
|
|
2844
2844
|
run: bun run cloud test:smoke
|
|
2845
|
-
`}function
|
|
2845
|
+
`}function kf(e){let{environments:t,awsRegion:n="us-east-1",awsRole:r}=e,i=!!r;return`name: Multi-Environment Deploy
|
|
2846
2846
|
|
|
2847
2847
|
on:
|
|
2848
2848
|
push:
|
|
@@ -2898,7 +2898,7 @@ ${t.map((s,a)=>` ${a>0?"elif":"if"} [[ "\${{ github.ref }}" == "refs/he
|
|
|
2898
2898
|
|
|
2899
2899
|
- name: Deploy
|
|
2900
2900
|
run: bun run cloud deploy --env=\${{ needs.determine-environment.outputs.environment }}
|
|
2901
|
-
`}function
|
|
2901
|
+
`}function Mf(e={}){let{awsRegion:t="us-east-1",awsRole:n,ttl:r=24}=e,i=!!n;return`name: PR Preview Environment
|
|
2902
2902
|
|
|
2903
2903
|
on:
|
|
2904
2904
|
pull_request:
|
|
@@ -3003,7 +3003,7 @@ jobs:
|
|
|
3003
3003
|
bun run cloud env:preview --destroy \\
|
|
3004
3004
|
--branch=\${{ github.head_ref }} \\
|
|
3005
3005
|
--pr=\${{ github.event.pull_request.number }}
|
|
3006
|
-
`}function
|
|
3006
|
+
`}function Lf(e){let{schedule:t,environment:n,awsRegion:r="us-east-1",awsRole:i}=e;return`name: Scheduled Deployment
|
|
3007
3007
|
|
|
3008
3008
|
on:
|
|
3009
3009
|
schedule:
|
|
@@ -3045,7 +3045,7 @@ jobs:
|
|
|
3045
3045
|
|
|
3046
3046
|
- name: Deploy
|
|
3047
3047
|
run: bun run cloud deploy --env=\${{ env.ENVIRONMENT }}
|
|
3048
|
-
`}function
|
|
3048
|
+
`}function Of(e){let{matrix:t,awsRole:n}=e,r=!!n;return`name: Matrix Deployment
|
|
3049
3049
|
|
|
3050
3050
|
on:
|
|
3051
3051
|
workflow_dispatch:
|
|
@@ -3092,7 +3092,7 @@ ${t.map((i)=>` - environment: ${i.environment}
|
|
|
3092
3092
|
|
|
3093
3093
|
- name: Deploy to \${{ matrix.environment }} (\${{ matrix.region }})
|
|
3094
3094
|
run: bun run cloud deploy --env=\${{ matrix.environment }} --region=\${{ matrix.region }}
|
|
3095
|
-
`}function
|
|
3095
|
+
`}function Bf(e={}){let{stages:t=["test","build","deploy"],environments:n=["production"],awsRegion:r="us-east-1",dockerImage:i="oven/bun:latest",deployCommand:s="bun run cloud deploy",testCommand:a="bun test",buildCommand:o="bun run build"}=e;return`stages:
|
|
3096
3096
|
${t.map((c)=>` - ${c}`).join(`
|
|
3097
3097
|
`)}
|
|
3098
3098
|
|
|
@@ -3140,7 +3140,7 @@ deploy:
|
|
|
3140
3140
|
only:
|
|
3141
3141
|
- main
|
|
3142
3142
|
when: manual
|
|
3143
|
-
`}function
|
|
3143
|
+
`}function Ff(e){let{environments:t,awsRegion:n="us-east-1"}=e,r=t.map((i)=>`
|
|
3144
3144
|
deploy:${i.name}:
|
|
3145
3145
|
stage: deploy
|
|
3146
3146
|
script:
|
|
@@ -3181,7 +3181,7 @@ build:
|
|
|
3181
3181
|
paths:
|
|
3182
3182
|
- dist/
|
|
3183
3183
|
${r}
|
|
3184
|
-
`}function
|
|
3184
|
+
`}function Gf(e={}){let{awsRegion:t="us-east-1",ttl:n=24}=e;return`stages:
|
|
3185
3185
|
- build
|
|
3186
3186
|
- deploy
|
|
3187
3187
|
- cleanup
|
|
@@ -3226,7 +3226,7 @@ cleanup:preview:
|
|
|
3226
3226
|
when: manual
|
|
3227
3227
|
only:
|
|
3228
3228
|
- merge_requests
|
|
3229
|
-
`}function
|
|
3229
|
+
`}function _f(e){let{environment:t,awsRegion:n="us-east-1"}=e;return`stages:
|
|
3230
3230
|
- deploy
|
|
3231
3231
|
|
|
3232
3232
|
variables:
|
|
@@ -3245,7 +3245,7 @@ deploy:scheduled:
|
|
|
3245
3245
|
name: \${ENVIRONMENT}
|
|
3246
3246
|
only:
|
|
3247
3247
|
- schedules
|
|
3248
|
-
`}function
|
|
3248
|
+
`}function Wf(e){let{environments:t,awsRegion:n="us-east-1"}=e,r=t.map((i)=>`
|
|
3249
3249
|
deploy:${i}:
|
|
3250
3250
|
stage: deploy
|
|
3251
3251
|
script:
|
|
@@ -3266,7 +3266,7 @@ variables:
|
|
|
3266
3266
|
default:
|
|
3267
3267
|
image: oven/bun:latest
|
|
3268
3268
|
${r}
|
|
3269
|
-
`}function
|
|
3269
|
+
`}function Uf(e={}){let{awsRegion:t="us-east-1",dockerImage:n="oven/bun:latest",deployCommand:r="bun run cloud deploy",testCommand:i="bun test",buildCommand:s="bun run build",workflows:a=!0}=e;return`version: 2.1
|
|
3270
3270
|
|
|
3271
3271
|
orbs:
|
|
3272
3272
|
aws-cli: circleci/aws-cli@4.0
|
|
@@ -3349,7 +3349,7 @@ ${a?`workflows:
|
|
|
3349
3349
|
branches:
|
|
3350
3350
|
only: main
|
|
3351
3351
|
`:""}
|
|
3352
|
-
`}function
|
|
3352
|
+
`}function Hf(e){let{environments:t,awsRegion:n="us-east-1"}=e,r=t.map((s)=>`
|
|
3353
3353
|
deploy-${s.name}:
|
|
3354
3354
|
executor: bun-executor
|
|
3355
3355
|
steps:
|
|
@@ -3425,7 +3425,7 @@ workflows:
|
|
|
3425
3425
|
requires:
|
|
3426
3426
|
- test
|
|
3427
3427
|
${i}
|
|
3428
|
-
`}function
|
|
3428
|
+
`}function jf(e){let{schedule:t,environment:n,awsRegion:r="us-east-1"}=e;return`version: 2.1
|
|
3429
3429
|
|
|
3430
3430
|
orbs:
|
|
3431
3431
|
aws-cli: circleci/aws-cli@4.0
|
|
@@ -3462,7 +3462,7 @@ workflows:
|
|
|
3462
3462
|
only: main
|
|
3463
3463
|
jobs:
|
|
3464
3464
|
- deploy
|
|
3465
|
-
`}function
|
|
3465
|
+
`}function Kf(e){let{environments:t,awsRegion:n="us-east-1"}=e,r=t.map((s)=>`
|
|
3466
3466
|
deploy-${s}:
|
|
3467
3467
|
executor: bun-executor
|
|
3468
3468
|
steps:
|
|
@@ -3538,7 +3538,7 @@ workflows:
|
|
|
3538
3538
|
requires:
|
|
3539
3539
|
- test
|
|
3540
3540
|
${i}
|
|
3541
|
-
`}function
|
|
3541
|
+
`}function qf(e){let{regions:t,environment:n}=e,r=t.map((s)=>`
|
|
3542
3542
|
deploy-${s.replace(/-/g,"_")}:
|
|
3543
3543
|
executor: bun-executor
|
|
3544
3544
|
environment:
|
|
@@ -3607,7 +3607,7 @@ workflows:
|
|
|
3607
3607
|
requires:
|
|
3608
3608
|
- test
|
|
3609
3609
|
${i}
|
|
3610
|
-
`}class ln{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 oc=new ln;class un{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 cc=new un;class dn{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 lc=new dn;class mn{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 uc=new mn;class pn{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 dc=new pn;class De{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",...De.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...De.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...De.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...De.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 mc=new De;class gn{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 pc=new gn;class lt{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=lt.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=lt.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 gc=new lt;class yn{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';
|
|
3610
|
+
`}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 vc=new yn;class hn{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 Tc=new hn;class fn{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 Rc=new fn;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 Pc=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 Ec=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 wc=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 Ic=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 Dc=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';
|
|
3611
3611
|
|
|
3612
3612
|
exports.handler = (event, _context, _callback) => {
|
|
3613
3613
|
const request = event.Records[0].cf.request;
|
|
@@ -3654,7 +3654,7 @@ exports.handler = (event, _context, _callback) => {
|
|
|
3654
3654
|
}`).join(" else ")}
|
|
3655
3655
|
|
|
3656
3656
|
callback(null, request);
|
|
3657
|
-
};`}clear(){this.tests.clear(),this.testCounter=0}}var yc=new yn;class hn{rollouts=new Map;flags=new Map;gates=new Map;counter=0;createProgressiveRollout(e,t){let n=`rollout-${Date.now()}-${this.counter++}`,r={id:n,name:e,stages:t,currentStage:0};return this.rollouts.set(n,r),r}createFeatureFlag(e,t=0){let n=`flag-${Date.now()}-${this.counter++}`,r={id:n,name:e,enabled:!1,rolloutPercentage:t,targetingRules:[]};return this.flags.set(n,r),r}createDeploymentGate(e,t,n,r){let i=`gate-${Date.now()}-${this.counter++}`,s={id:i,name:e,type:t,approvers:n,conditions:r};return this.gates.set(i,s),s}clear(){this.rollouts.clear(),this.flags.clear(),this.gates.clear()}}var hc=new hn;class di{configs=new Map;samplingRules=new Map;configCounter=0;ruleCounter=0;createConfig(e){let t=`xray-config-${Date.now()}-${this.configCounter++}`,n={id:t,...e};return this.configs.set(t,n),n}createLambdaConfig(e){return this.createConfig({name:`${e.functionName}-xray`,serviceName:e.functionName,samplingRate:e.samplingRate||0.1,enableActiveTracing:!0})}createECSConfig(e){return this.createConfig({name:`${e.serviceName}-xray`,serviceName:`${e.clusterName}/${e.serviceName}`,samplingRate:e.samplingRate||0.05,enableActiveTracing:!0})}createAPIGatewayConfig(e){return this.createConfig({name:`${e.apiName}-${e.stage}-xray`,serviceName:`${e.apiName}/${e.stage}`,samplingRate:e.samplingRate||0.05,enableActiveTracing:!0})}createSamplingRule(e){let t=`sampling-rule-${Date.now()}-${this.ruleCounter++}`,n={id:t,...e};return this.samplingRules.set(t,n),n}createHighPrioritySamplingRule(e){return this.createSamplingRule({ruleName:e.ruleName,priority:100,fixedRate:1,reservoirSize:100,serviceName:e.serviceName,serviceType:"*",host:"*",httpMethod:"*",urlPath:e.urlPath,version:1})}createErrorSamplingRule(e){return this.createSamplingRule({ruleName:`${e}-errors`,priority:200,fixedRate:1,reservoirSize:50,serviceName:e,serviceType:"*",host:"*",httpMethod:"*",urlPath:"/error/*",version:1})}createDefaultSamplingRule(e,t=0.05){return this.createSamplingRule({ruleName:`${e}-default`,priority:1000,fixedRate:t,reservoirSize:10,serviceName:e,serviceType:"*",host:"*",httpMethod:"*",urlPath:"*",version:1})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getSamplingRule(e){return this.samplingRules.get(e)}listSamplingRules(){return Array.from(this.samplingRules.values())}generateLambdaXRayCF(e){return{TracingConfig:{Mode:e.enableActiveTracing?"Active":"PassThrough"}}}generateAPIGatewayXRayCF(e){return{TracingEnabled:e.enableActiveTracing}}generateECSXRaySidecarCF(){return{Name:"xray-daemon",Image:"public.ecr.aws/xray/aws-xray-daemon:latest",Cpu:32,MemoryReservation:256,PortMappings:[{ContainerPort:2000,Protocol:"udp"}]}}generateSamplingRuleCF(e){return{Type:"AWS::XRay::SamplingRule",Properties:{SamplingRule:{RuleName:e.ruleName,Priority:e.priority,FixedRate:e.fixedRate,ReservoirSize:e.reservoirSize,ServiceName:e.serviceName,ServiceType:e.serviceType,Host:e.host,HTTPMethod:e.httpMethod,URLPath:e.urlPath,Version:e.version,ResourceARN:"*"}}}}createTrace(e,t){return{id:`trace-${Date.now()}-${this.configCounter++}`,traceId:e,spans:t}}clear(){this.configs.clear(),this.samplingRules.clear(),this.configCounter=0,this.ruleCounter=0}}var qf=new di;class mi{namespaces=new Map;metrics=new Map;namespaceCounter=0;metricCounter=0;alarmCounter=0;createNamespace(e){let t=`namespace-${Date.now()}-${this.namespaceCounter++}`,n={id:t,...e};return this.namespaces.set(t,n),n}createMetric(e){let t=`metric-${Date.now()}-${this.metricCounter++}`,n={id:t,...e};return this.metrics.set(t,n),n}createBusinessMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:e.unit,dimensions:[{name:"Environment",value:"production"},{name:"Type",value:"Business"}]})}createApplicationMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:e.unit,dimensions:[{name:"Service",value:e.serviceName},{name:"Type",value:"Application"}]})}createPerformanceMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:"Milliseconds",dimensions:[{name:"Operation",value:e.operation},{name:"Type",value:"Performance"}]})}createErrorMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:"Count",dimensions:[{name:"ErrorType",value:e.errorType},{name:"Type",value:"Error"}]})}createAlarm(e,t){let n=this.metrics.get(e);if(!n)throw Error(`Metric not found: ${e}`);let i={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...t};if(!n.alarms)n.alarms=[];return n.alarms.push(i),i}createErrorRateAlarm(e){return this.createAlarm(e.metricId,{name:e.name,description:`Alert when error rate exceeds ${e.threshold} errors/min`,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:2,threshold:e.threshold,period:60,statistic:"Sum",treatMissingData:"notBreaching",actionsEnabled:!0,alarmActions:e.snsTopicArn?[e.snsTopicArn]:void 0})}createLatencyAlarm(e){return this.createAlarm(e.metricId,{name:e.name,description:`Alert when latency exceeds ${e.thresholdMs}ms`,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,threshold:e.thresholdMs,period:300,statistic:"Average",treatMissingData:"notBreaching",actionsEnabled:!0,alarmActions:e.snsTopicArn?[e.snsTopicArn]:void 0})}createThroughputAlarm(e){return this.createAlarm(e.metricId,{name:e.name,description:`Alert when throughput drops below ${e.minimumThreshold}`,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,threshold:e.minimumThreshold,period:300,statistic:"Sum",treatMissingData:"breaching",actionsEnabled:!0,alarmActions:e.snsTopicArn?[e.snsTopicArn]:void 0})}createCompositeAlarm(e){return{name:e.name,description:e.description,alarmRule:e.alarmRule,actionsEnabled:e.actionsEnabled??!0,alarmActions:e.alarmActions}}getNamespace(e){return this.namespaces.get(e)}listNamespaces(){return Array.from(this.namespaces.values())}getMetric(e){return this.metrics.get(e)}listMetrics(){return Array.from(this.metrics.values())}generateAlarmCF(e,t){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:t.name,AlarmDescription:t.description,ComparisonOperator:t.comparisonOperator,EvaluationPeriods:t.evaluationPeriods,MetricName:e.name,Namespace:e.namespace,Period:t.period,Statistic:t.statistic,Threshold:t.threshold,TreatMissingData:t.treatMissingData||"notBreaching",ActionsEnabled:t.actionsEnabled??!0,...t.alarmActions&&{AlarmActions:t.alarmActions},...t.okActions&&{OKActions:t.okActions},...t.insufficientDataActions&&{InsufficientDataActions:t.insufficientDataActions},...e.dimensions&&{Dimensions:e.dimensions.map((n)=>({Name:n.name,Value:n.value}))}}}}generateCompositeAlarmCF(e){return{Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:e.name,AlarmDescription:e.description,AlarmRule:e.alarmRule,ActionsEnabled:e.actionsEnabled,...e.alarmActions&&{AlarmActions:e.alarmActions}}}}generateDashboardWidget(e){return{type:"metric",properties:{metrics:[[e.namespace,e.name,...e.dimensions?.flatMap((t)=>[t.name,t.value])||[]]],period:300,stat:"Average",region:"us-east-1",title:e.name}}}publishCustomMetric(e,t,n,r={},i="Count"){return{id:`metric-${Date.now()}-${this.metricCounter++}`,namespace:e,name:t,dimensions:r,value:n,unit:i,timestamp:new Date}}clear(){this.namespaces.clear(),this.metrics.clear(),this.namespaceCounter=0,this.metricCounter=0,this.alarmCounter=0}}var Qf=new mi;class fn{logGroups=new Map;queries=new Map;insightsQueries=new Map;logGroupCounter=0;filterCounter=0;queryCounter=0;createLogGroup(e){let t=`log-group-${Date.now()}-${this.logGroupCounter++}`,n={id:t,...e};return this.logGroups.set(t,n),n}createLambdaLogGroup(e,t=7){return this.createLogGroup({name:`/aws/lambda/${e}`,retentionDays:t})}createECSLogGroup(e){return this.createLogGroup({name:`/ecs/${e.clusterName}/${e.serviceName}`,retentionDays:e.retentionDays||14})}createAPIGatewayLogGroup(e,t,n=30){return this.createLogGroup({name:`/aws/apigateway/${e}/${t}`,retentionDays:n})}createApplicationLogGroup(e){return this.createLogGroup({name:`/application/${e.appName}/${e.environment}`,retentionDays:e.retentionDays||30,kmsKeyId:e.kmsKeyId})}createMetricFilter(e,t){let n=this.logGroups.get(e);if(!n)throw Error(`Log group not found: ${e}`);let i={id:`filter-${Date.now()}-${this.filterCounter++}`,...t};if(!n.metricFilters)n.metricFilters=[];return n.metricFilters.push(i),i}createErrorCountFilter(e,t){return this.createMetricFilter(e,{name:"ErrorCount",filterPattern:"[timestamp, request_id, level = ERROR*, ...]",metricTransformations:[{metricName:"ErrorCount",metricNamespace:t,metricValue:"1",defaultValue:0,unit:"Count"}]})}createLatencyFilter(e,t){return this.createMetricFilter(e,{name:"Latency",filterPattern:"[timestamp, request_id, level, duration, ...]",metricTransformations:[{metricName:"ResponseTime",metricNamespace:t,metricValue:"$duration",unit:"Milliseconds"}]})}createCustomPatternFilter(e){return this.createMetricFilter(e.logGroupId,{name:e.name,filterPattern:e.pattern,metricTransformations:[{metricName:e.metricName,metricNamespace:e.namespace,metricValue:"1",defaultValue:0,unit:"Count"}]})}createSubscriptionFilter(e,t){let n=this.logGroups.get(e);if(!n)throw Error(`Log group not found: ${e}`);let i={id:`subscription-${Date.now()}-${this.filterCounter++}`,...t};if(!n.subscriptionFilters)n.subscriptionFilters=[];return n.subscriptionFilters.push(i),i}createKinesisSubscription(e){let t=this.logGroups.get(e.logGroupId);if(!t)throw Error(`Log group not found: ${e.logGroupId}`);return this.createSubscriptionFilter(e.logGroupId,{name:"KinesisSubscription",logGroupName:t.name,filterPattern:e.filterPattern||"",destinationArn:e.kinesisStreamArn,roleArn:e.roleArn,distribution:"Random"})}createLambdaSubscription(e){let t=this.logGroups.get(e.logGroupId);if(!t)throw Error(`Log group not found: ${e.logGroupId}`);return this.createSubscriptionFilter(e.logGroupId,{name:"LambdaSubscription",logGroupName:t.name,filterPattern:e.filterPattern||"",destinationArn:e.lambdaFunctionArn,distribution:"ByLogStream"})}createInsightsQuery(e){let t=`query-${Date.now()}-${this.queryCounter++}`,n={id:t,...e};return this.insightsQueries.set(t,n),n}createErrorAnalysisQuery(e){return this.createInsightsQuery({name:"Error Analysis",description:"Analyze error patterns and frequencies",query:`fields @timestamp, @message
|
|
3657
|
+
};`}clear(){this.tests.clear(),this.testCounter=0}}var Nc=new Cn;class vn{rollouts=new Map;flags=new Map;gates=new Map;counter=0;createProgressiveRollout(e,t){let n=`rollout-${Date.now()}-${this.counter++}`,r={id:n,name:e,stages:t,currentStage:0};return this.rollouts.set(n,r),r}createFeatureFlag(e,t=0){let n=`flag-${Date.now()}-${this.counter++}`,r={id:n,name:e,enabled:!1,rolloutPercentage:t,targetingRules:[]};return this.flags.set(n,r),r}createDeploymentGate(e,t,n,r){let i=`gate-${Date.now()}-${this.counter++}`,s={id:i,name:e,type:t,approvers:n,conditions:r};return this.gates.set(i,s),s}clear(){this.rollouts.clear(),this.flags.clear(),this.gates.clear()}}var xc=new vn;class Ci{configs=new Map;samplingRules=new Map;configCounter=0;ruleCounter=0;createConfig(e){let t=`xray-config-${Date.now()}-${this.configCounter++}`,n={id:t,...e};return this.configs.set(t,n),n}createLambdaConfig(e){return this.createConfig({name:`${e.functionName}-xray`,serviceName:e.functionName,samplingRate:e.samplingRate||0.1,enableActiveTracing:!0})}createECSConfig(e){return this.createConfig({name:`${e.serviceName}-xray`,serviceName:`${e.clusterName}/${e.serviceName}`,samplingRate:e.samplingRate||0.05,enableActiveTracing:!0})}createAPIGatewayConfig(e){return this.createConfig({name:`${e.apiName}-${e.stage}-xray`,serviceName:`${e.apiName}/${e.stage}`,samplingRate:e.samplingRate||0.05,enableActiveTracing:!0})}createSamplingRule(e){let t=`sampling-rule-${Date.now()}-${this.ruleCounter++}`,n={id:t,...e};return this.samplingRules.set(t,n),n}createHighPrioritySamplingRule(e){return this.createSamplingRule({ruleName:e.ruleName,priority:100,fixedRate:1,reservoirSize:100,serviceName:e.serviceName,serviceType:"*",host:"*",httpMethod:"*",urlPath:e.urlPath,version:1})}createErrorSamplingRule(e){return this.createSamplingRule({ruleName:`${e}-errors`,priority:200,fixedRate:1,reservoirSize:50,serviceName:e,serviceType:"*",host:"*",httpMethod:"*",urlPath:"/error/*",version:1})}createDefaultSamplingRule(e,t=0.05){return this.createSamplingRule({ruleName:`${e}-default`,priority:1000,fixedRate:t,reservoirSize:10,serviceName:e,serviceType:"*",host:"*",httpMethod:"*",urlPath:"*",version:1})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getSamplingRule(e){return this.samplingRules.get(e)}listSamplingRules(){return Array.from(this.samplingRules.values())}generateLambdaXRayCF(e){return{TracingConfig:{Mode:e.enableActiveTracing?"Active":"PassThrough"}}}generateAPIGatewayXRayCF(e){return{TracingEnabled:e.enableActiveTracing}}generateECSXRaySidecarCF(){return{Name:"xray-daemon",Image:"public.ecr.aws/xray/aws-xray-daemon:latest",Cpu:32,MemoryReservation:256,PortMappings:[{ContainerPort:2000,Protocol:"udp"}]}}generateSamplingRuleCF(e){return{Type:"AWS::XRay::SamplingRule",Properties:{SamplingRule:{RuleName:e.ruleName,Priority:e.priority,FixedRate:e.fixedRate,ReservoirSize:e.reservoirSize,ServiceName:e.serviceName,ServiceType:e.serviceType,Host:e.host,HTTPMethod:e.httpMethod,URLPath:e.urlPath,Version:e.version,ResourceARN:"*"}}}}createTrace(e,t){return{id:`trace-${Date.now()}-${this.configCounter++}`,traceId:e,spans:t}}clear(){this.configs.clear(),this.samplingRules.clear(),this.configCounter=0,this.ruleCounter=0}}var fb=new Ci;class vi{namespaces=new Map;metrics=new Map;namespaceCounter=0;metricCounter=0;alarmCounter=0;createNamespace(e){let t=`namespace-${Date.now()}-${this.namespaceCounter++}`,n={id:t,...e};return this.namespaces.set(t,n),n}createMetric(e){let t=`metric-${Date.now()}-${this.metricCounter++}`,n={id:t,...e};return this.metrics.set(t,n),n}createBusinessMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:e.unit,dimensions:[{name:"Environment",value:"production"},{name:"Type",value:"Business"}]})}createApplicationMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:e.unit,dimensions:[{name:"Service",value:e.serviceName},{name:"Type",value:"Application"}]})}createPerformanceMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:"Milliseconds",dimensions:[{name:"Operation",value:e.operation},{name:"Type",value:"Performance"}]})}createErrorMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:"Count",dimensions:[{name:"ErrorType",value:e.errorType},{name:"Type",value:"Error"}]})}createAlarm(e,t){let n=this.metrics.get(e);if(!n)throw Error(`Metric not found: ${e}`);let i={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...t};if(!n.alarms)n.alarms=[];return n.alarms.push(i),i}createErrorRateAlarm(e){return this.createAlarm(e.metricId,{name:e.name,description:`Alert when error rate exceeds ${e.threshold} errors/min`,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:2,threshold:e.threshold,period:60,statistic:"Sum",treatMissingData:"notBreaching",actionsEnabled:!0,alarmActions:e.snsTopicArn?[e.snsTopicArn]:void 0})}createLatencyAlarm(e){return this.createAlarm(e.metricId,{name:e.name,description:`Alert when latency exceeds ${e.thresholdMs}ms`,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,threshold:e.thresholdMs,period:300,statistic:"Average",treatMissingData:"notBreaching",actionsEnabled:!0,alarmActions:e.snsTopicArn?[e.snsTopicArn]:void 0})}createThroughputAlarm(e){return this.createAlarm(e.metricId,{name:e.name,description:`Alert when throughput drops below ${e.minimumThreshold}`,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,threshold:e.minimumThreshold,period:300,statistic:"Sum",treatMissingData:"breaching",actionsEnabled:!0,alarmActions:e.snsTopicArn?[e.snsTopicArn]:void 0})}createCompositeAlarm(e){return{name:e.name,description:e.description,alarmRule:e.alarmRule,actionsEnabled:e.actionsEnabled??!0,alarmActions:e.alarmActions}}getNamespace(e){return this.namespaces.get(e)}listNamespaces(){return Array.from(this.namespaces.values())}getMetric(e){return this.metrics.get(e)}listMetrics(){return Array.from(this.metrics.values())}generateAlarmCF(e,t){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:t.name,AlarmDescription:t.description,ComparisonOperator:t.comparisonOperator,EvaluationPeriods:t.evaluationPeriods,MetricName:e.name,Namespace:e.namespace,Period:t.period,Statistic:t.statistic,Threshold:t.threshold,TreatMissingData:t.treatMissingData||"notBreaching",ActionsEnabled:t.actionsEnabled??!0,...t.alarmActions&&{AlarmActions:t.alarmActions},...t.okActions&&{OKActions:t.okActions},...t.insufficientDataActions&&{InsufficientDataActions:t.insufficientDataActions},...e.dimensions&&{Dimensions:e.dimensions.map((n)=>({Name:n.name,Value:n.value}))}}}}generateCompositeAlarmCF(e){return{Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:e.name,AlarmDescription:e.description,AlarmRule:e.alarmRule,ActionsEnabled:e.actionsEnabled,...e.alarmActions&&{AlarmActions:e.alarmActions}}}}generateDashboardWidget(e){return{type:"metric",properties:{metrics:[[e.namespace,e.name,...e.dimensions?.flatMap((t)=>[t.name,t.value])||[]]],period:300,stat:"Average",region:"us-east-1",title:e.name}}}publishCustomMetric(e,t,n,r={},i="Count"){return{id:`metric-${Date.now()}-${this.metricCounter++}`,namespace:e,name:t,dimensions:r,value:n,unit:i,timestamp:new Date}}clear(){this.namespaces.clear(),this.metrics.clear(),this.namespaceCounter=0,this.metricCounter=0,this.alarmCounter=0}}var Sb=new vi;class Tn{logGroups=new Map;queries=new Map;insightsQueries=new Map;logGroupCounter=0;filterCounter=0;queryCounter=0;createLogGroup(e){let t=`log-group-${Date.now()}-${this.logGroupCounter++}`,n={id:t,...e};return this.logGroups.set(t,n),n}createLambdaLogGroup(e,t=7){return this.createLogGroup({name:`/aws/lambda/${e}`,retentionDays:t})}createECSLogGroup(e){return this.createLogGroup({name:`/ecs/${e.clusterName}/${e.serviceName}`,retentionDays:e.retentionDays||14})}createAPIGatewayLogGroup(e,t,n=30){return this.createLogGroup({name:`/aws/apigateway/${e}/${t}`,retentionDays:n})}createApplicationLogGroup(e){return this.createLogGroup({name:`/application/${e.appName}/${e.environment}`,retentionDays:e.retentionDays||30,kmsKeyId:e.kmsKeyId})}createMetricFilter(e,t){let n=this.logGroups.get(e);if(!n)throw Error(`Log group not found: ${e}`);let i={id:`filter-${Date.now()}-${this.filterCounter++}`,...t};if(!n.metricFilters)n.metricFilters=[];return n.metricFilters.push(i),i}createErrorCountFilter(e,t){return this.createMetricFilter(e,{name:"ErrorCount",filterPattern:"[timestamp, request_id, level = ERROR*, ...]",metricTransformations:[{metricName:"ErrorCount",metricNamespace:t,metricValue:"1",defaultValue:0,unit:"Count"}]})}createLatencyFilter(e,t){return this.createMetricFilter(e,{name:"Latency",filterPattern:"[timestamp, request_id, level, duration, ...]",metricTransformations:[{metricName:"ResponseTime",metricNamespace:t,metricValue:"$duration",unit:"Milliseconds"}]})}createCustomPatternFilter(e){return this.createMetricFilter(e.logGroupId,{name:e.name,filterPattern:e.pattern,metricTransformations:[{metricName:e.metricName,metricNamespace:e.namespace,metricValue:"1",defaultValue:0,unit:"Count"}]})}createSubscriptionFilter(e,t){let n=this.logGroups.get(e);if(!n)throw Error(`Log group not found: ${e}`);let i={id:`subscription-${Date.now()}-${this.filterCounter++}`,...t};if(!n.subscriptionFilters)n.subscriptionFilters=[];return n.subscriptionFilters.push(i),i}createKinesisSubscription(e){let t=this.logGroups.get(e.logGroupId);if(!t)throw Error(`Log group not found: ${e.logGroupId}`);return this.createSubscriptionFilter(e.logGroupId,{name:"KinesisSubscription",logGroupName:t.name,filterPattern:e.filterPattern||"",destinationArn:e.kinesisStreamArn,roleArn:e.roleArn,distribution:"Random"})}createLambdaSubscription(e){let t=this.logGroups.get(e.logGroupId);if(!t)throw Error(`Log group not found: ${e.logGroupId}`);return this.createSubscriptionFilter(e.logGroupId,{name:"LambdaSubscription",logGroupName:t.name,filterPattern:e.filterPattern||"",destinationArn:e.lambdaFunctionArn,distribution:"ByLogStream"})}createInsightsQuery(e){let t=`query-${Date.now()}-${this.queryCounter++}`,n={id:t,...e};return this.insightsQueries.set(t,n),n}createErrorAnalysisQuery(e){return this.createInsightsQuery({name:"Error Analysis",description:"Analyze error patterns and frequencies",query:`fields @timestamp, @message
|
|
3658
3658
|
| filter @message like /ERROR/
|
|
3659
3659
|
| stats count() by bin(5m)
|
|
3660
3660
|
| sort @timestamp desc`,logGroupNames:e})}createLatencyAnalysisQuery(e){return this.createInsightsQuery({name:"Latency Analysis",description:"Analyze request latency patterns",query:`fields @timestamp, @duration
|
|
@@ -3664,7 +3664,7 @@ exports.handler = (event, _context, _callback) => {
|
|
|
3664
3664
|
| filter @message like /ERROR/
|
|
3665
3665
|
| stats count() as error_count by @message
|
|
3666
3666
|
| sort error_count desc
|
|
3667
|
-
| 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
|
|
3667
|
+
| 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 kc=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=`
|
|
3668
3668
|
const synthetics = require('Synthetics');
|
|
3669
3669
|
const log = require('SyntheticsLogger');
|
|
3670
3670
|
|
|
@@ -3684,7 +3684,7 @@ const heartbeat = async function () {
|
|
|
3684
3684
|
exports.handler = async () => {
|
|
3685
3685
|
return await heartbeat();
|
|
3686
3686
|
};
|
|
3687
|
-
`;return this.createCanary({name:e.name,description:`Heartbeat monitor for ${e.url}`,runtimeVersion:
|
|
3687
|
+
`;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=`
|
|
3688
3688
|
const synthetics = require('Synthetics');
|
|
3689
3689
|
const log = require('SyntheticsLogger');
|
|
3690
3690
|
|
|
@@ -3713,7 +3713,7 @@ const apiCheck = async function () {
|
|
|
3713
3713
|
exports.handler = async () => {
|
|
3714
3714
|
return await apiCheck();
|
|
3715
3715
|
};
|
|
3716
|
-
`;return this.createCanary({name:e.name,description:`API monitor for ${e.baseUrl}`,runtimeVersion:
|
|
3716
|
+
`;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=`
|
|
3717
3717
|
const synthetics = require('Synthetics');
|
|
3718
3718
|
const log = require('SyntheticsLogger');
|
|
3719
3719
|
|
|
@@ -3733,7 +3733,7 @@ const visualCheck = async function () {
|
|
|
3733
3733
|
exports.handler = async () => {
|
|
3734
3734
|
return await visualCheck();
|
|
3735
3735
|
};
|
|
3736
|
-
`;return this.createCanary({name:e.name,description:`Visual regression monitor for ${e.url}`,runtimeVersion:
|
|
3736
|
+
`;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=`
|
|
3737
3737
|
const synthetics = require('Synthetics');
|
|
3738
3738
|
const log = require('SyntheticsLogger');
|
|
3739
3739
|
|
|
@@ -3755,35 +3755,35 @@ const workflowCheck = async function () {
|
|
|
3755
3755
|
exports.handler = async () => {
|
|
3756
3756
|
return await workflowCheck();
|
|
3757
3757
|
};
|
|
3758
|
-
`;return this.createCanary({name:e.name,description:e.description,runtimeVersion:
|
|
3758
|
+
`;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 Mc=new xe;class Ti{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}
|
|
3759
3759
|
`),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
|
|
3760
3760
|
`)}else console.log(`[SKIPPED - DRY RUN]
|
|
3761
3761
|
`);i.push(o.version)}catch(c){if(console.error(`✗ Failed: ${c instanceof Error?c.message:String(c)}
|
|
3762
3762
|
`),s.push(o.version),!t)return console.log("Rolling back previously applied migrations..."),await this.rollbackMigrations(i.reverse(),n),{success:!1,version:o.version,appliedMigrations:[],failedMigrations:s,executionTimeMs:Date.now()-r,error:c instanceof Error?c.message:String(c),rollbackPerformed:!0}}let a=Date.now()-r;return console.log(`${t?"[DRY RUN] ":""}Migration plan completed successfully`),console.log(`Total time: ${a}ms`),{success:!0,version:n.migrations[n.migrations.length-1]?.version||"unknown",appliedMigrations:i,failedMigrations:s,executionTimeMs:a}}async rollbackMigrations(e,t){for(let n of e){let r=t.migrations.find((i)=>i.version===n);if(r)console.log(`Rolling back: ${r.version} - ${r.name}`),r.rolledBackAt=new Date,console.log(`✓ Rolled back
|
|
3763
3763
|
`)}}getMigrationStatus(e){let t=this.plans.get(e);if(!t)throw Error(`Migration plan not found: ${e}`);let n=t.migrations.filter((i)=>i.appliedAt&&!i.rolledBackAt),r=t.migrations.filter((i)=>!i.appliedAt);return{currentVersion:n[n.length-1]?.version||"0.0.0",pendingMigrations:r,appliedMigrations:n,lastMigration:n[n.length-1]}}generateSchemaSQL(e,t,n="postgres"){let r=[],i=[];for(let s of e)switch(s.type){case"add_column":r.push(`ALTER TABLE ${t} ADD COLUMN ${s.columnName} ${s.columnType}${s.nullable===!1?" NOT NULL":""}${s.defaultValue?` DEFAULT ${s.defaultValue}`:""}; `),i.push(`ALTER TABLE ${t} DROP COLUMN ${s.columnName};`);break;case"drop_column":r.push(`ALTER TABLE ${t} DROP COLUMN ${s.columnName};`),i.push(`-- Cannot restore dropped column ${s.columnName}`);break;case"modify_column":if(n==="postgres")r.push(`ALTER TABLE ${t} ALTER COLUMN ${s.columnName} TYPE ${s.newType};`);else r.push(`ALTER TABLE ${t} MODIFY COLUMN ${s.columnName} ${s.newType};`);i.push(`-- Reverting ${s.columnName} type change requires manual intervention`);break;case"add_index":r.push(`CREATE INDEX ${s.indexName} ON ${t} (${(s.columns??[]).join(", ")});`),i.push(`DROP INDEX ${s.indexName};`);break;case"drop_index":r.push(`DROP INDEX ${s.indexName};`),i.push(`-- Cannot restore index ${s.indexName} without schema details`);break}return{up:r.join(`
|
|
3764
3764
|
`),down:i.reverse().join(`
|
|
3765
|
-
`)}}generateChecksum(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 t.toString(16)}validatePlan(e){let t=this.plans.get(e);if(!t)return{valid:!1,errors:["Migration plan not found"]};let n=[],r=new Set;for(let i of t.migrations){if(r.has(i.version))n.push(`Duplicate migration version: ${i.version}`);r.add(i.version)}for(let i of t.migrations)if(!i.down||i.down.trim()==="")n.push(`Migration ${i.version} is missing rollback SQL`);for(let i of t.migrations)if(this.generateChecksum(i.up+i.down)!==i.checksum)n.push(`Migration ${i.version} has invalid checksum`);return{valid:n.length===0,errors:n}}getPlan(e){return this.plans.get(e)}listPlans(){return Array.from(this.plans.values())}getMigration(e){return this.migrations.get(e)}listMigrations(){return Array.from(this.migrations.values())}clear(){this.plans.clear(),this.migrations.clear(),this.planCounter=0,this.migrationCounter=0}}var
|
|
3765
|
+
`)}}generateChecksum(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 t.toString(16)}validatePlan(e){let t=this.plans.get(e);if(!t)return{valid:!1,errors:["Migration plan not found"]};let n=[],r=new Set;for(let i of t.migrations){if(r.has(i.version))n.push(`Duplicate migration version: ${i.version}`);r.add(i.version)}for(let i of t.migrations)if(!i.down||i.down.trim()==="")n.push(`Migration ${i.version} is missing rollback SQL`);for(let i of t.migrations)if(this.generateChecksum(i.up+i.down)!==i.checksum)n.push(`Migration ${i.version} has invalid checksum`);return{valid:n.length===0,errors:n}}getPlan(e){return this.plans.get(e)}listPlans(){return Array.from(this.plans.values())}getMigration(e){return this.migrations.get(e)}listMigrations(){return Array.from(this.migrations.values())}clear(){this.plans.clear(),this.migrations.clear(),this.planCounter=0,this.migrationCounter=0}}var Tb=new Ti;class Rn{replicas=new Map;replicationGroups=new Map;proxies=new Map;proxyTargets=new Map;replicaCounter=0;groupCounter=0;proxyCounter=0;targetCounter=0;createReplica(e){let t=`replica-${Date.now()}-${this.replicaCounter++}`,n={id:t,status:"creating",...e};return this.replicas.set(t,n),n}createRDSReplica(e){return this.createReplica({name:e.name,sourceDatabase:e.sourceDatabase,region:e.region||"us-east-1",instanceClass:e.instanceClass||"db.t3.medium",multiAZ:e.multiAZ||!1,autoMinorVersionUpgrade:!0,backupRetentionPeriod:7})}createCrossRegionReplica(e){return this.createReplica({name:e.name,sourceDatabase:e.sourceDatabase,region:e.targetRegion,instanceClass:e.instanceClass||"db.t3.medium",multiAZ:!0,autoMinorVersionUpgrade:!0,backupRetentionPeriod:7})}createReplicationGroup(e){let t=`replication-group-${Date.now()}-${this.groupCounter++}`,n={id:t,...e};return this.replicationGroups.set(t,n),n}createAutoScalingReplicationGroup(e){return this.createReplicationGroup({name:e.name,primaryDatabase:e.primaryDatabase,replicas:[],loadBalancing:e.loadBalancing||{type:"round-robin"},failoverEnabled:!0,autoScaling:{enabled:!0,minReplicas:e.minReplicas,maxReplicas:e.maxReplicas,targetCPU:e.targetCPU||70,scaleUpCooldown:300,scaleDownCooldown:600}})}addReplicaToGroup(e,t){let n=this.replicationGroups.get(e);if(!n)throw Error(`Replication group not found: ${e}`);n.replicas.push(t)}createProxy(e){let t=`rds-proxy-${Date.now()}-${this.proxyCounter++}`,n={id:t,...e};return this.proxies.set(t,n),n}createConnectionPoolProxy(e){return this.createProxy({name:e.name,engineFamily:e.engineFamily,targetDatabase:e.targetDatabase,maxConnectionsPercent:e.maxConnections||100,maxIdleConnectionsPercent:50,connectionBorrowTimeout:120,sessionPinningFilters:["EXCLUDE_VARIABLE_SETS"],requireTLS:!0,idleClientTimeout:1800,vpcSubnetIds:e.vpcSubnetIds,securityGroupIds:e.securityGroupIds,secretArn:e.secretArn})}createServerlessProxy(e){return this.createProxy({name:e.name,engineFamily:e.engineFamily,targetDatabase:e.targetDatabase,maxConnectionsPercent:100,maxIdleConnectionsPercent:10,connectionBorrowTimeout:60,sessionPinningFilters:["EXCLUDE_VARIABLE_SETS"],requireTLS:!0,idleClientTimeout:300,vpcSubnetIds:e.vpcSubnetIds,securityGroupIds:e.securityGroupIds,secretArn:e.secretArn})}addProxyTarget(e){let t=`proxy-target-${Date.now()}-${this.targetCounter++}`,n={id:t,...e};return this.proxyTargets.set(t,n),n}promoteReplica(e){let t=this.replicas.get(e);if(!t)return{success:!1,message:"Replica not found"};if(console.log(`Promoting replica to primary: ${t.name}`),console.log(`Region: ${t.region}`),console.log(`
|
|
3766
3766
|
1. Checking replication lag...`),t.replicationLag&&t.replicationLag>5000)return{success:!1,message:`Replication lag too high: ${t.replicationLag}ms`};return console.log(` Replication lag: ${t.replicationLag||0}ms (acceptable)`),console.log(`
|
|
3767
3767
|
2. Promoting replica to standalone instance...`),console.log(`
|
|
3768
3768
|
3. Updating DNS records...`),console.log(`
|
|
3769
3769
|
4. Updating application configuration...`),console.log(`
|
|
3770
|
-
✓ Promotion completed successfully`),t.status="available",{success:!0,message:"Replica promoted successfully"}}getReplicationLag(e){if(!this.replicas.get(e))throw Error(`Replica not found: ${e}`);return Math.floor(Math.random()*1000)}getReplica(e){return this.replicas.get(e)}listReplicas(){return Array.from(this.replicas.values())}getReplicationGroup(e){return this.replicationGroups.get(e)}listReplicationGroups(){return Array.from(this.replicationGroups.values())}getProxy(e){return this.proxies.get(e)}listProxies(){return Array.from(this.proxies.values())}generateReplicaCF(e){return{Type:"AWS::RDS::DBInstance",Properties:{SourceDBInstanceIdentifier:e.sourceDatabase,DBInstanceIdentifier:e.name,DBInstanceClass:e.instanceClass,MultiAZ:e.multiAZ||!1,AutoMinorVersionUpgrade:e.autoMinorVersionUpgrade??!0,...e.backupRetentionPeriod&&{BackupRetentionPeriod:e.backupRetentionPeriod},...e.preferredBackupWindow&&{PreferredBackupWindow:e.preferredBackupWindow},...e.preferredMaintenanceWindow&&{PreferredMaintenanceWindow:e.preferredMaintenanceWindow}}}}generateProxyCF(e){return{Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:e.name,EngineFamily:e.engineFamily,Auth:[{AuthScheme:"SECRETS",SecretArn:e.secretArn,IAMAuth:"DISABLED"}],RoleArn:{"Fn::GetAtt":["RDSProxyRole","Arn"]},VpcSubnetIds:e.vpcSubnetIds,VpcSecurityGroupIds:e.securityGroupIds,RequireTLS:e.requireTLS??!0,IdleClientTimeout:e.idleClientTimeout||1800,...e.maxConnectionsPercent&&{MaxConnectionsPercent:e.maxConnectionsPercent},...e.maxIdleConnectionsPercent&&{MaxIdleConnectionsPercent:e.maxIdleConnectionsPercent},...e.connectionBorrowTimeout&&{ConnectionBorrowTimeout:e.connectionBorrowTimeout}}}}generateProxyTargetCF(e,t){return{Type:"AWS::RDS::DBProxyTargetGroup",Properties:{DBProxyName:t.name,TargetGroupName:"default",DBInstanceIdentifiers:[e.targetArn],ConnectionPoolConfig:{MaxConnectionsPercent:100,MaxIdleConnectionsPercent:50,ConnectionBorrowTimeout:120}}}}generateProxyRoleCF(){return{Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"RDSProxySecretsPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],Resource:"arn:aws:secretsmanager:*:*:secret:*"},{Effect:"Allow",Action:["kms:Decrypt"],Resource:"arn:aws:kms:*:*:key/*",Condition:{StringEquals:{"kms:ViaService":"secretsmanager.*.amazonaws.com"}}}]}}]}}}clear(){this.replicas.clear(),this.replicationGroups.clear(),this.proxies.clear(),this.proxyTargets.clear(),this.replicaCounter=0,this.groupCounter=0,this.proxyCounter=0,this.targetCounter=0}}var Sc=new bn;class gi{insights=new Map;slowQueryLogs=new Map;queryMetrics=new Map;reports=new Map;indexRecommendations=new Map;insightsCounter=0;logCounter=0;metricCounter=0;reportCounter=0;recommendationCounter=0;enablePerformanceInsights(e){let t=`pi-${Date.now()}-${this.insightsCounter++}`,n={id:t,name:e.name,databaseIdentifier:e.databaseIdentifier,enabled:!0,retentionPeriod:e.retentionPeriod||7,kmsKeyId:e.kmsKeyId};return this.insights.set(t,n),n}enableSlowQueryLog(e){let t=`slow-query-${Date.now()}-${this.logCounter++}`,n={id:t,name:e.name,databaseIdentifier:e.databaseIdentifier,enabled:!0,logDestination:e.logDestination,cloudwatchLogGroup:e.cloudwatchLogGroup,s3Bucket:e.s3Bucket,s3Prefix:e.s3Bucket?"slow-queries/":void 0,minExecutionTime:e.minExecutionTime||1000};return this.slowQueryLogs.set(t,n),n}recordQueryMetric(e){let t=`metric-${Date.now()}-${this.metricCounter++}`,n={id:t,timestamp:new Date,...e};return this.queryMetrics.set(t,n),n}generatePerformanceReport(e){let t=`report-${Date.now()}-${this.reportCounter++}`,n={avgCPU:Math.random()*60+20,maxCPU:Math.random()*30+70,avgConnections:Math.floor(Math.random()*50+10),maxConnections:Math.floor(Math.random()*50+100),avgReadIOPS:Math.floor(Math.random()*1000+500),avgWriteIOPS:Math.floor(Math.random()*500+200),avgReadThroughput:Math.random()*50+10,avgWriteThroughput:Math.random()*20+5,avgReadLatency:Math.random()*5+1,avgWriteLatency:Math.random()*8+2,cacheHitRatio:Math.random()*10+90,deadlocks:Math.floor(Math.random()*5),longRunningTransactions:Math.floor(Math.random()*10)},r=Array.from(this.queryMetrics.values()),i=r.sort((c,l)=>l.executionCount-c.executionCount).slice(0,10),s=r.filter((c)=>c.avgExecutionTime>1000).sort((c,l)=>l.avgExecutionTime-c.avgExecutionTime).slice(0,10),a=this.generateRecommendations(n,s),o={id:t,name:e.name,databaseIdentifier:e.databaseIdentifier,reportType:e.reportType,metrics:n,topQueries:i,slowQueries:s,recommendations:a,generatedAt:new Date};return this.reports.set(t,o),o}generateRecommendations(e,t){let n=[];if(e.avgCPU>70)n.push({type:"scaling",severity:"high",title:"High CPU Usage",description:`Average CPU usage is ${e.avgCPU.toFixed(1)}%, which is above the recommended threshold of 70%.`,impact:"Performance degradation, increased latency, potential timeouts",effort:"medium"});if(e.cacheHitRatio<95)n.push({type:"configuration",severity:"medium",title:"Low Cache Hit Ratio",description:`Cache hit ratio is ${e.cacheHitRatio.toFixed(1)}%. Consider increasing buffer pool size.`,impact:"Increased disk I/O, slower query performance",effort:"low"});if(e.deadlocks>0)n.push({type:"query",severity:"medium",title:"Deadlocks Detected",description:`${e.deadlocks} deadlock(s) detected. Review transaction isolation levels and query patterns.`,impact:"Transaction failures, application errors",effort:"high"});if(t.length>0)n.push({type:"index",severity:"high",title:"Slow Queries Detected",description:`${t.length} slow queries detected. Consider adding indexes or optimizing queries.`,impact:"High latency, poor user experience",effort:"medium"});if(e.avgReadLatency>10||e.avgWriteLatency>10)n.push({type:"scaling",severity:"high",title:"High I/O Latency",description:"Read or write latency is high. Consider upgrading to Provisioned IOPS or moving to a larger instance.",impact:"Slow query execution, application timeouts",effort:"medium"});return n}analyzeQuery(e){let t=`analysis-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,n=[{id:1,operation:"Seq Scan",table:"users",rows:1e4,cost:850.5,children:[]}],r=[];if(e.toLowerCase().includes("select *"))r.push({type:"full_table_scan",severity:"warning",description:"Query selects all columns. Consider selecting only required columns."});if(!e.toLowerCase().includes("where")&&e.toLowerCase().includes("select"))r.push({type:"full_table_scan",severity:"critical",description:"Query has no WHERE clause and may scan entire table."});return{id:t,queryId:t,sql:e,executionPlan:n,bottlenecks:r,recommendations:["Add appropriate indexes on WHERE clause columns","Consider using EXPLAIN ANALYZE to get actual execution statistics","Review and optimize JOIN conditions"],estimatedCost:n[0].cost}}recommendIndex(e){let t=`index-rec-${Date.now()}-${this.recommendationCounter++}`,n=`idx_${e.tableName}_${e.columns.join("_")}`,r={id:t,tableName:e.tableName,columns:e.columns,reason:e.reason,estimatedImprovement:e.estimatedImprovement||50,estimatedSize:e.columns.length*10,createSQL:`CREATE INDEX ${n} ON ${e.tableName} (${e.columns.join(", ")});`};return this.indexRecommendations.set(t,r),r}getInsights(e){return this.insights.get(e)}listInsights(){return Array.from(this.insights.values())}getSlowQueryLog(e){return this.slowQueryLogs.get(e)}listSlowQueryLogs(){return Array.from(this.slowQueryLogs.values())}getReport(e){return this.reports.get(e)}listReports(){return Array.from(this.reports.values())}listIndexRecommendations(){return Array.from(this.indexRecommendations.values())}generatePerformanceInsightsCF(e){return{EnablePerformanceInsights:e.enabled,PerformanceInsightsRetentionPeriod:e.retentionPeriod,...e.kmsKeyId&&{PerformanceInsightsKMSKeyId:e.kmsKeyId}}}generateSlowQueryAlarmCF(e){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:"Alert when slow queries exceed threshold",MetricName:"SlowQueryCount",Namespace:"AWS/RDS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",...e.snsTopicArn&&{AlarmActions:[e.snsTopicArn]}}}}clear(){this.insights.clear(),this.slowQueryLogs.clear(),this.queryMetrics.clear(),this.reports.clear(),this.indexRecommendations.clear(),this.insightsCounter=0,this.logCounter=0,this.metricCounter=0,this.reportCounter=0,this.recommendationCounter=0}}var nb=new gi;class yi{users=new Map;roles=new Map;audits=new Map;userCounter=0;roleCounter=0;auditCounter=0;createUser(e){let t=`db-user-${Date.now()}-${this.userCounter++}`,n={id:t,createdAt:new Date,...e};return this.users.set(t,n),n}createReadOnlyUser(e){let t=e.tables?e.tables.map((n)=>({database:e.database,table:n,privileges:["SELECT"]})):[{database:e.database,privileges:["SELECT"]}];return this.createUser({username:e.username,database:e.database,privileges:t,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:90})}createReadWriteUser(e){let t=e.tables?e.tables.map((n)=>({database:e.database,table:n,privileges:["SELECT","INSERT","UPDATE","DELETE"]})):[{database:e.database,privileges:["SELECT","INSERT","UPDATE","DELETE"]}];return this.createUser({username:e.username,database:e.database,privileges:t,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:60})}createAdminUser(e){return this.createUser({username:e.username,database:e.database,privileges:[{database:e.database,privileges:["ALL"]}],passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:30})}createApplicationUser(e){let t=e.tables.map((n)=>({database:e.database,table:n.name,privileges:n.privileges}));return this.createUser({username:e.username,database:e.database,privileges:t,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:90})}createRole(e){let t=`role-${Date.now()}-${this.roleCounter++}`,n={id:t,users:[],...e};return this.roles.set(t,n),n}assignUserToRole(e,t){let n=this.users.get(e),r=this.roles.get(t);if(!n)throw Error(`User not found: ${e}`);if(!r)throw Error(`Role not found: ${t}`);r.users.push(e);for(let i of r.privileges){let s=n.privileges.find((a)=>a.database===i.database&&a.table===i.table);if(s)s.privileges=Array.from(new Set([...s.privileges,...i.privileges]));else n.privileges.push({...i})}}grantPrivileges(e,t){let n=this.users.get(e);if(!n)return{success:!1,message:"User not found"};for(let r of t){let i=n.privileges.find((s)=>s.database===r.database&&s.table===r.table);if(i)i.privileges=Array.from(new Set([...i.privileges,...r.privileges]));else n.privileges.push(r)}return this.auditAccess({username:n.username,action:"GRANT",database:t[0]?.database,table:t[0]?.table,success:!0}),{success:!0,message:"Privileges granted successfully"}}revokePrivileges(e,t){let n=this.users.get(e);if(!n)return{success:!1,message:"User not found"};for(let r of t){let i=n.privileges.findIndex((s)=>s.database===r.database&&s.table===r.table);if(i!==-1){let s=n.privileges[i];if(s.privileges=s.privileges.filter((a)=>!r.privileges.includes(a)),s.privileges.length===0)n.privileges.splice(i,1)}}return this.auditAccess({username:n.username,action:"REVOKE",database:t[0]?.database,table:t[0]?.table,success:!0}),{success:!0,message:"Privileges revoked successfully"}}rotatePassword(e){let t=this.users.get(e);if(!t)return{success:!1};let n=`arn:aws:secretsmanager:us-east-1:123456789012:secret:db-${t.username}-${Date.now()}`;return t.passwordSecretArn=n,t.lastRotated=new Date,console.log(`Password rotated for user: ${t.username}`),{success:!0,newSecretArn:n}}needsPasswordRotation(e){let t=this.users.get(e);if(!t||!t.rotationEnabled||!t.lastRotated||!t.rotationDays)return!1;return(Date.now()-t.lastRotated.getTime())/86400000>=t.rotationDays}auditAccess(e){let t=`audit-${Date.now()}-${this.auditCounter++}`,n={id:t,timestamp:new Date,...e};return this.audits.set(t,n),n}getUserAccessHistory(e,t=100){return Array.from(this.audits.values()).filter((n)=>n.username===e).sort((n,r)=>r.timestamp.getTime()-n.timestamp.getTime()).slice(0,t)}getFailedLoginAttempts(e,t=24){let n=Date.now()-t*60*60*1000;return Array.from(this.audits.values()).filter((r)=>r.username===e&&r.action==="LOGIN"&&!r.success&&r.timestamp.getTime()>n)}generateCreateUserSQL(e,t="postgres"){let n=[];if(t==="postgres"){n.push(`CREATE USER ${e.username} WITH PASSWORD '${e.passwordSecretArn}';`);for(let r of e.privileges)if(r.privileges.includes("ALL"))n.push(`GRANT ALL PRIVILEGES ON DATABASE ${r.database} TO ${e.username};`);else{let i=r.privileges.join(", ");if(r.table)n.push(`GRANT ${i} ON ${r.database}.${r.table} TO ${e.username};`);else n.push(`GRANT ${i} ON DATABASE ${r.database} TO ${e.username};`)}}else{n.push(`CREATE USER '${e.username}'@'%' IDENTIFIED BY '${e.passwordSecretArn}';`);for(let r of e.privileges){let i=r.privileges.includes("ALL")?"ALL PRIVILEGES":r.privileges.join(", "),s=r.table?`${r.database}.${r.table}`:`${r.database}.*`;n.push(`GRANT ${i} ON ${s} TO '${e.username}'@'%';`)}n.push("FLUSH PRIVILEGES;")}return n.join(`
|
|
3771
|
-
`)}getUser(e){return this.users.get(e)}listUsers(){return Array.from(this.users.values())}getRole(e){return this.roles.get(e)}listRoles(){return Array.from(this.roles.values())}clear(){this.users.clear(),this.roles.clear(),this.audits.clear(),this.userCounter=0,this.roleCounter=0,this.auditCounter=0}}var
|
|
3770
|
+
✓ Promotion completed successfully`),t.status="available",{success:!0,message:"Replica promoted successfully"}}getReplicationLag(e){if(!this.replicas.get(e))throw Error(`Replica not found: ${e}`);return Math.floor(Math.random()*1000)}getReplica(e){return this.replicas.get(e)}listReplicas(){return Array.from(this.replicas.values())}getReplicationGroup(e){return this.replicationGroups.get(e)}listReplicationGroups(){return Array.from(this.replicationGroups.values())}getProxy(e){return this.proxies.get(e)}listProxies(){return Array.from(this.proxies.values())}generateReplicaCF(e){return{Type:"AWS::RDS::DBInstance",Properties:{SourceDBInstanceIdentifier:e.sourceDatabase,DBInstanceIdentifier:e.name,DBInstanceClass:e.instanceClass,MultiAZ:e.multiAZ||!1,AutoMinorVersionUpgrade:e.autoMinorVersionUpgrade??!0,...e.backupRetentionPeriod&&{BackupRetentionPeriod:e.backupRetentionPeriod},...e.preferredBackupWindow&&{PreferredBackupWindow:e.preferredBackupWindow},...e.preferredMaintenanceWindow&&{PreferredMaintenanceWindow:e.preferredMaintenanceWindow}}}}generateProxyCF(e){return{Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:e.name,EngineFamily:e.engineFamily,Auth:[{AuthScheme:"SECRETS",SecretArn:e.secretArn,IAMAuth:"DISABLED"}],RoleArn:{"Fn::GetAtt":["RDSProxyRole","Arn"]},VpcSubnetIds:e.vpcSubnetIds,VpcSecurityGroupIds:e.securityGroupIds,RequireTLS:e.requireTLS??!0,IdleClientTimeout:e.idleClientTimeout||1800,...e.maxConnectionsPercent&&{MaxConnectionsPercent:e.maxConnectionsPercent},...e.maxIdleConnectionsPercent&&{MaxIdleConnectionsPercent:e.maxIdleConnectionsPercent},...e.connectionBorrowTimeout&&{ConnectionBorrowTimeout:e.connectionBorrowTimeout}}}}generateProxyTargetCF(e,t){return{Type:"AWS::RDS::DBProxyTargetGroup",Properties:{DBProxyName:t.name,TargetGroupName:"default",DBInstanceIdentifiers:[e.targetArn],ConnectionPoolConfig:{MaxConnectionsPercent:100,MaxIdleConnectionsPercent:50,ConnectionBorrowTimeout:120}}}}generateProxyRoleCF(){return{Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"RDSProxySecretsPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],Resource:"arn:aws:secretsmanager:*:*:secret:*"},{Effect:"Allow",Action:["kms:Decrypt"],Resource:"arn:aws:kms:*:*:key/*",Condition:{StringEquals:{"kms:ViaService":"secretsmanager.*.amazonaws.com"}}}]}}]}}}clear(){this.replicas.clear(),this.replicationGroups.clear(),this.proxies.clear(),this.proxyTargets.clear(),this.replicaCounter=0,this.groupCounter=0,this.proxyCounter=0,this.targetCounter=0}}var Lc=new Rn;class Ri{insights=new Map;slowQueryLogs=new Map;queryMetrics=new Map;reports=new Map;indexRecommendations=new Map;insightsCounter=0;logCounter=0;metricCounter=0;reportCounter=0;recommendationCounter=0;enablePerformanceInsights(e){let t=`pi-${Date.now()}-${this.insightsCounter++}`,n={id:t,name:e.name,databaseIdentifier:e.databaseIdentifier,enabled:!0,retentionPeriod:e.retentionPeriod||7,kmsKeyId:e.kmsKeyId};return this.insights.set(t,n),n}enableSlowQueryLog(e){let t=`slow-query-${Date.now()}-${this.logCounter++}`,n={id:t,name:e.name,databaseIdentifier:e.databaseIdentifier,enabled:!0,logDestination:e.logDestination,cloudwatchLogGroup:e.cloudwatchLogGroup,s3Bucket:e.s3Bucket,s3Prefix:e.s3Bucket?"slow-queries/":void 0,minExecutionTime:e.minExecutionTime||1000};return this.slowQueryLogs.set(t,n),n}recordQueryMetric(e){let t=`metric-${Date.now()}-${this.metricCounter++}`,n={id:t,timestamp:new Date,...e};return this.queryMetrics.set(t,n),n}generatePerformanceReport(e){let t=`report-${Date.now()}-${this.reportCounter++}`,n={avgCPU:Math.random()*60+20,maxCPU:Math.random()*30+70,avgConnections:Math.floor(Math.random()*50+10),maxConnections:Math.floor(Math.random()*50+100),avgReadIOPS:Math.floor(Math.random()*1000+500),avgWriteIOPS:Math.floor(Math.random()*500+200),avgReadThroughput:Math.random()*50+10,avgWriteThroughput:Math.random()*20+5,avgReadLatency:Math.random()*5+1,avgWriteLatency:Math.random()*8+2,cacheHitRatio:Math.random()*10+90,deadlocks:Math.floor(Math.random()*5),longRunningTransactions:Math.floor(Math.random()*10)},r=Array.from(this.queryMetrics.values()),i=r.sort((c,l)=>l.executionCount-c.executionCount).slice(0,10),s=r.filter((c)=>c.avgExecutionTime>1000).sort((c,l)=>l.avgExecutionTime-c.avgExecutionTime).slice(0,10),a=this.generateRecommendations(n,s),o={id:t,name:e.name,databaseIdentifier:e.databaseIdentifier,reportType:e.reportType,metrics:n,topQueries:i,slowQueries:s,recommendations:a,generatedAt:new Date};return this.reports.set(t,o),o}generateRecommendations(e,t){let n=[];if(e.avgCPU>70)n.push({type:"scaling",severity:"high",title:"High CPU Usage",description:`Average CPU usage is ${e.avgCPU.toFixed(1)}%, which is above the recommended threshold of 70%.`,impact:"Performance degradation, increased latency, potential timeouts",effort:"medium"});if(e.cacheHitRatio<95)n.push({type:"configuration",severity:"medium",title:"Low Cache Hit Ratio",description:`Cache hit ratio is ${e.cacheHitRatio.toFixed(1)}%. Consider increasing buffer pool size.`,impact:"Increased disk I/O, slower query performance",effort:"low"});if(e.deadlocks>0)n.push({type:"query",severity:"medium",title:"Deadlocks Detected",description:`${e.deadlocks} deadlock(s) detected. Review transaction isolation levels and query patterns.`,impact:"Transaction failures, application errors",effort:"high"});if(t.length>0)n.push({type:"index",severity:"high",title:"Slow Queries Detected",description:`${t.length} slow queries detected. Consider adding indexes or optimizing queries.`,impact:"High latency, poor user experience",effort:"medium"});if(e.avgReadLatency>10||e.avgWriteLatency>10)n.push({type:"scaling",severity:"high",title:"High I/O Latency",description:"Read or write latency is high. Consider upgrading to Provisioned IOPS or moving to a larger instance.",impact:"Slow query execution, application timeouts",effort:"medium"});return n}analyzeQuery(e){let t=`analysis-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,n=[{id:1,operation:"Seq Scan",table:"users",rows:1e4,cost:850.5,children:[]}],r=[];if(e.toLowerCase().includes("select *"))r.push({type:"full_table_scan",severity:"warning",description:"Query selects all columns. Consider selecting only required columns."});if(!e.toLowerCase().includes("where")&&e.toLowerCase().includes("select"))r.push({type:"full_table_scan",severity:"critical",description:"Query has no WHERE clause and may scan entire table."});return{id:t,queryId:t,sql:e,executionPlan:n,bottlenecks:r,recommendations:["Add appropriate indexes on WHERE clause columns","Consider using EXPLAIN ANALYZE to get actual execution statistics","Review and optimize JOIN conditions"],estimatedCost:n[0].cost}}recommendIndex(e){let t=`index-rec-${Date.now()}-${this.recommendationCounter++}`,n=`idx_${e.tableName}_${e.columns.join("_")}`,r={id:t,tableName:e.tableName,columns:e.columns,reason:e.reason,estimatedImprovement:e.estimatedImprovement||50,estimatedSize:e.columns.length*10,createSQL:`CREATE INDEX ${n} ON ${e.tableName} (${e.columns.join(", ")});`};return this.indexRecommendations.set(t,r),r}getInsights(e){return this.insights.get(e)}listInsights(){return Array.from(this.insights.values())}getSlowQueryLog(e){return this.slowQueryLogs.get(e)}listSlowQueryLogs(){return Array.from(this.slowQueryLogs.values())}getReport(e){return this.reports.get(e)}listReports(){return Array.from(this.reports.values())}listIndexRecommendations(){return Array.from(this.indexRecommendations.values())}generatePerformanceInsightsCF(e){return{EnablePerformanceInsights:e.enabled,PerformanceInsightsRetentionPeriod:e.retentionPeriod,...e.kmsKeyId&&{PerformanceInsightsKMSKeyId:e.kmsKeyId}}}generateSlowQueryAlarmCF(e){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:"Alert when slow queries exceed threshold",MetricName:"SlowQueryCount",Namespace:"AWS/RDS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",...e.snsTopicArn&&{AlarmActions:[e.snsTopicArn]}}}}clear(){this.insights.clear(),this.slowQueryLogs.clear(),this.queryMetrics.clear(),this.reports.clear(),this.indexRecommendations.clear(),this.insightsCounter=0,this.logCounter=0,this.metricCounter=0,this.reportCounter=0,this.recommendationCounter=0}}var Eb=new Ri;class Pi{users=new Map;roles=new Map;audits=new Map;userCounter=0;roleCounter=0;auditCounter=0;createUser(e){let t=`db-user-${Date.now()}-${this.userCounter++}`,n={id:t,createdAt:new Date,...e};return this.users.set(t,n),n}createReadOnlyUser(e){let t=e.tables?e.tables.map((n)=>({database:e.database,table:n,privileges:["SELECT"]})):[{database:e.database,privileges:["SELECT"]}];return this.createUser({username:e.username,database:e.database,privileges:t,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:90})}createReadWriteUser(e){let t=e.tables?e.tables.map((n)=>({database:e.database,table:n,privileges:["SELECT","INSERT","UPDATE","DELETE"]})):[{database:e.database,privileges:["SELECT","INSERT","UPDATE","DELETE"]}];return this.createUser({username:e.username,database:e.database,privileges:t,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:60})}createAdminUser(e){return this.createUser({username:e.username,database:e.database,privileges:[{database:e.database,privileges:["ALL"]}],passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:30})}createApplicationUser(e){let t=e.tables.map((n)=>({database:e.database,table:n.name,privileges:n.privileges}));return this.createUser({username:e.username,database:e.database,privileges:t,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:90})}createRole(e){let t=`role-${Date.now()}-${this.roleCounter++}`,n={id:t,users:[],...e};return this.roles.set(t,n),n}assignUserToRole(e,t){let n=this.users.get(e),r=this.roles.get(t);if(!n)throw Error(`User not found: ${e}`);if(!r)throw Error(`Role not found: ${t}`);r.users.push(e);for(let i of r.privileges){let s=n.privileges.find((a)=>a.database===i.database&&a.table===i.table);if(s)s.privileges=Array.from(new Set([...s.privileges,...i.privileges]));else n.privileges.push({...i})}}grantPrivileges(e,t){let n=this.users.get(e);if(!n)return{success:!1,message:"User not found"};for(let r of t){let i=n.privileges.find((s)=>s.database===r.database&&s.table===r.table);if(i)i.privileges=Array.from(new Set([...i.privileges,...r.privileges]));else n.privileges.push(r)}return this.auditAccess({username:n.username,action:"GRANT",database:t[0]?.database,table:t[0]?.table,success:!0}),{success:!0,message:"Privileges granted successfully"}}revokePrivileges(e,t){let n=this.users.get(e);if(!n)return{success:!1,message:"User not found"};for(let r of t){let i=n.privileges.findIndex((s)=>s.database===r.database&&s.table===r.table);if(i!==-1){let s=n.privileges[i];if(s.privileges=s.privileges.filter((a)=>!r.privileges.includes(a)),s.privileges.length===0)n.privileges.splice(i,1)}}return this.auditAccess({username:n.username,action:"REVOKE",database:t[0]?.database,table:t[0]?.table,success:!0}),{success:!0,message:"Privileges revoked successfully"}}rotatePassword(e){let t=this.users.get(e);if(!t)return{success:!1};let n=`arn:aws:secretsmanager:us-east-1:123456789012:secret:db-${t.username}-${Date.now()}`;return t.passwordSecretArn=n,t.lastRotated=new Date,console.log(`Password rotated for user: ${t.username}`),{success:!0,newSecretArn:n}}needsPasswordRotation(e){let t=this.users.get(e);if(!t||!t.rotationEnabled||!t.lastRotated||!t.rotationDays)return!1;return(Date.now()-t.lastRotated.getTime())/86400000>=t.rotationDays}auditAccess(e){let t=`audit-${Date.now()}-${this.auditCounter++}`,n={id:t,timestamp:new Date,...e};return this.audits.set(t,n),n}getUserAccessHistory(e,t=100){return Array.from(this.audits.values()).filter((n)=>n.username===e).sort((n,r)=>r.timestamp.getTime()-n.timestamp.getTime()).slice(0,t)}getFailedLoginAttempts(e,t=24){let n=Date.now()-t*60*60*1000;return Array.from(this.audits.values()).filter((r)=>r.username===e&&r.action==="LOGIN"&&!r.success&&r.timestamp.getTime()>n)}generateCreateUserSQL(e,t="postgres"){let n=[];if(t==="postgres"){n.push(`CREATE USER ${e.username} WITH PASSWORD '${e.passwordSecretArn}';`);for(let r of e.privileges)if(r.privileges.includes("ALL"))n.push(`GRANT ALL PRIVILEGES ON DATABASE ${r.database} TO ${e.username};`);else{let i=r.privileges.join(", ");if(r.table)n.push(`GRANT ${i} ON ${r.database}.${r.table} TO ${e.username};`);else n.push(`GRANT ${i} ON DATABASE ${r.database} TO ${e.username};`)}}else{n.push(`CREATE USER '${e.username}'@'%' IDENTIFIED BY '${e.passwordSecretArn}';`);for(let r of e.privileges){let i=r.privileges.includes("ALL")?"ALL PRIVILEGES":r.privileges.join(", "),s=r.table?`${r.database}.${r.table}`:`${r.database}.*`;n.push(`GRANT ${i} ON ${s} TO '${e.username}'@'%';`)}n.push("FLUSH PRIVILEGES;")}return n.join(`
|
|
3771
|
+
`)}getUser(e){return this.users.get(e)}listUsers(){return Array.from(this.users.values())}getRole(e){return this.roles.get(e)}listRoles(){return Array.from(this.roles.values())}clear(){this.users.clear(),this.roles.clear(),this.audits.clear(),this.userCounter=0,this.roleCounter=0,this.auditCounter=0}}var Ib=new Pi;class Ei{rotations=new Map;schedules=new Map;rotationCounter=0;scheduleCounter=0;createRotation(e){let t=`rotation-${Date.now()}-${this.rotationCounter++}`,n={id:t,...e};return this.rotations.set(t,n),n}enableRDSRotation(e){let t=this.createRotation({secretId:e.secretId,secretType:"rds_credentials",rotationEnabled:!0,rotationDays:e.rotationDays||30,rotationLambdaArn:this.generateRDSRotationLambdaArn(e.engine)});return t.nextRotation=new Date(Date.now()+t.rotationDays*24*60*60*1000),t}enableAPIKeyRotation(e){return this.createRotation({secretId:e.secretId,secretType:"api_key",rotationEnabled:!0,rotationDays:e.rotationDays||90,rotationLambdaArn:e.rotationLambdaArn})}enableOAuthRotation(e){return this.createRotation({secretId:e.secretId,secretType:"oauth_token",rotationEnabled:!0,rotationDays:e.rotationDays||60,rotationLambdaArn:e.rotationLambdaArn})}enableSSHKeyRotation(e){return this.createRotation({secretId:e.secretId,secretType:"ssh_key",rotationEnabled:!0,rotationDays:e.rotationDays||180,rotationLambdaArn:e.rotationLambdaArn})}createSchedule(e){let t=`schedule-${Date.now()}-${this.scheduleCounter++}`,n={id:t,...e};return this.schedules.set(t,n),n}async executeRotation(e){let t=this.rotations.get(e);if(!t)throw Error(`Rotation not found: ${e}`);console.log(`
|
|
3772
3772
|
Executing rotation for secret: ${t.secretId}`),console.log(`Secret type: ${t.secretType}`),console.log(`Rotation interval: ${t.rotationDays} days`);try{console.log(`
|
|
3773
3773
|
Rotation steps:`),console.log("1. Creating new secret version...");let n=`v${Date.now()}`;console.log("2. Testing new credentials..."),console.log("3. Updating application references..."),console.log("4. Marking previous version as deprecated...");let r=t.versionStages?.[0]||"v1";return console.log("5. Finalizing rotation..."),t.lastRotated=new Date,t.nextRotation=new Date(Date.now()+t.rotationDays*24*60*60*1000),console.log(`
|
|
3774
3774
|
✓ Rotation completed successfully`),console.log(` New version: ${n}`),console.log(` Next rotation: ${t.nextRotation.toISOString()}`),{success:!0,secretId:t.secretId,oldVersion:r,newVersion:n,rotatedAt:new Date}}catch(n){return console.error(`
|
|
3775
|
-
✗ Rotation failed:`,n),{success:!1,secretId:t.secretId,oldVersion:"unknown",newVersion:"unknown",rotatedAt:new Date,error:n instanceof Error?n.message:String(n)}}}needsRotation(e){let t=this.rotations.get(e);if(!t||!t.rotationEnabled)return!1;if(!t.lastRotated)return!0;return(Date.now()-t.lastRotated.getTime())/86400000>=t.rotationDays}getSecretsNeedingRotation(){return Array.from(this.rotations.values()).filter((e)=>this.needsRotation(e.id))}generateRDSRotationLambdaArn(e){let t={postgres:"SecretsManagerRDSPostgreSQLRotationSingleUser",mysql:"SecretsManagerRDSMySQLRotationSingleUser",sqlserver:"SecretsManagerRDSSQLServerRotationSingleUser",oracle:"SecretsManagerRDSOracleRotationSingleUser"};return`arn:aws:lambda:us-east-1:123456789012:function:${t[e]||t.postgres}`}getRotation(e){return this.rotations.get(e)}listRotations(){return Array.from(this.rotations.values())}getSchedule(e){return this.schedules.get(e)}listSchedules(){return Array.from(this.schedules.values())}generateRotationCF(e){return{RotationEnabled:e.rotationEnabled,RotationRules:{AutomaticallyAfterDays:e.rotationDays},...e.rotationLambdaArn&&{RotationLambdaARN:e.rotationLambdaArn}}}generateRotationLambdaCF(e){return{Type:"AWS::Lambda::Function",Properties:{FunctionName:e.functionName,Runtime:"python3.11",Handler:"lambda_function.lambda_handler",Role:{"Fn::GetAtt":["RotationLambdaRole","Arn"]},Timeout:30,Environment:{Variables:{SECRETS_MANAGER_ENDPOINT:"https://secretsmanager.us-east-1.amazonaws.com"}},...e.vpcConfig&&{VpcConfig:{SubnetIds:e.vpcConfig.subnetIds,SecurityGroupIds:e.vpcConfig.securityGroupIds}}}}}generateRotationLambdaRoleCF(){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/service-role/AWSLambdaVPCAccessExecutionRole"],Policies:[{PolicyName:"SecretsRotationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:DescribeSecret","secretsmanager:GetSecretValue","secretsmanager:PutSecretValue","secretsmanager:UpdateSecretVersionStage"],Resource:"*"},{Effect:"Allow",Action:["secretsmanager:GetRandomPassword"],Resource:"*"}]}}]}}}generateRotationScheduleCF(e){return{Type:"AWS::Events::Rule",Properties:{Name:e.name,Description:`Rotation schedule for ${e.secrets.length} secrets`,ScheduleExpression:e.schedule,State:e.enabled?"ENABLED":"DISABLED",Targets:[{Arn:{"Fn::GetAtt":["RotationStateMachine","Arn"]},RoleArn:{"Fn::GetAtt":["EventBridgeRotationRole","Arn"]},Input:JSON.stringify({secrets:e.secrets})}]}}}clear(){this.rotations.clear(),this.schedules.clear(),this.rotationCounter=0,this.scheduleCounter=0}}var
|
|
3775
|
+
✗ Rotation failed:`,n),{success:!1,secretId:t.secretId,oldVersion:"unknown",newVersion:"unknown",rotatedAt:new Date,error:n instanceof Error?n.message:String(n)}}}needsRotation(e){let t=this.rotations.get(e);if(!t||!t.rotationEnabled)return!1;if(!t.lastRotated)return!0;return(Date.now()-t.lastRotated.getTime())/86400000>=t.rotationDays}getSecretsNeedingRotation(){return Array.from(this.rotations.values()).filter((e)=>this.needsRotation(e.id))}generateRDSRotationLambdaArn(e){let t={postgres:"SecretsManagerRDSPostgreSQLRotationSingleUser",mysql:"SecretsManagerRDSMySQLRotationSingleUser",sqlserver:"SecretsManagerRDSSQLServerRotationSingleUser",oracle:"SecretsManagerRDSOracleRotationSingleUser"};return`arn:aws:lambda:us-east-1:123456789012:function:${t[e]||t.postgres}`}getRotation(e){return this.rotations.get(e)}listRotations(){return Array.from(this.rotations.values())}getSchedule(e){return this.schedules.get(e)}listSchedules(){return Array.from(this.schedules.values())}generateRotationCF(e){return{RotationEnabled:e.rotationEnabled,RotationRules:{AutomaticallyAfterDays:e.rotationDays},...e.rotationLambdaArn&&{RotationLambdaARN:e.rotationLambdaArn}}}generateRotationLambdaCF(e){return{Type:"AWS::Lambda::Function",Properties:{FunctionName:e.functionName,Runtime:"python3.11",Handler:"lambda_function.lambda_handler",Role:{"Fn::GetAtt":["RotationLambdaRole","Arn"]},Timeout:30,Environment:{Variables:{SECRETS_MANAGER_ENDPOINT:"https://secretsmanager.us-east-1.amazonaws.com"}},...e.vpcConfig&&{VpcConfig:{SubnetIds:e.vpcConfig.subnetIds,SecurityGroupIds:e.vpcConfig.securityGroupIds}}}}}generateRotationLambdaRoleCF(){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/service-role/AWSLambdaVPCAccessExecutionRole"],Policies:[{PolicyName:"SecretsRotationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:DescribeSecret","secretsmanager:GetSecretValue","secretsmanager:PutSecretValue","secretsmanager:UpdateSecretVersionStage"],Resource:"*"},{Effect:"Allow",Action:["secretsmanager:GetRandomPassword"],Resource:"*"}]}}]}}}generateRotationScheduleCF(e){return{Type:"AWS::Events::Rule",Properties:{Name:e.name,Description:`Rotation schedule for ${e.secrets.length} secrets`,ScheduleExpression:e.schedule,State:e.enabled?"ENABLED":"DISABLED",Targets:[{Arn:{"Fn::GetAtt":["RotationStateMachine","Arn"]},RoleArn:{"Fn::GetAtt":["EventBridgeRotationRole","Arn"]},Input:JSON.stringify({secrets:e.secrets})}]}}}clear(){this.rotations.clear(),this.schedules.clear(),this.rotationCounter=0,this.scheduleCounter=0}}var Nb=new Ei;class Pn{versions=new Map;audits=new Map;externalManagers=new Map;replications=new Map;policies=new Map;versionCounter=0;auditCounter=0;managerCounter=0;replicationCounter=0;policyCounter=0;createVersion(e){let t=`version-${Date.now()}-${this.versionCounter++}`,n={id:t,...e};return this.versions.set(t,n),this.auditAction({secretId:e.secretId,action:"CREATE",actor:"system",versionId:e.versionId,success:!0}),n}getVersionByStage(e,t){return Array.from(this.versions.values()).find((n)=>n.secretId===e&&n.versionStages.includes(t))}listVersions(e){return Array.from(this.versions.values()).filter((t)=>t.secretId===e).sort((t,n)=>n.createdAt.getTime()-t.createdAt.getTime())}deprecateVersion(e){let t=Array.from(this.versions.values()).find((n)=>n.versionId===e);if(t)t.deprecatedAt=new Date,t.versionStages=t.versionStages.filter((n)=>n!=="AWSCURRENT"),this.auditAction({secretId:t.secretId,action:"UPDATE",actor:"system",versionId:e,success:!0})}restoreVersion(e){let t=Array.from(this.versions.values()).find((n)=>n.versionId===e);if(t)Array.from(this.versions.values()).filter((n)=>n.secretId===t.secretId&&n.versionId!==e).forEach((n)=>{n.versionStages=n.versionStages.filter((r)=>r!=="AWSCURRENT")}),t.versionStages.push("AWSCURRENT"),t.deprecatedAt=void 0,this.auditAction({secretId:t.secretId,action:"RESTORE",actor:"system",versionId:e,success:!0})}auditAction(e){let t=`audit-${Date.now()}-${this.auditCounter++}`,n={id:t,timestamp:new Date,...e};return this.audits.set(t,n),n}getAuditTrail(e,t=100){return Array.from(this.audits.values()).filter((n)=>n.secretId===e).sort((n,r)=>r.timestamp.getTime()-n.timestamp.getTime()).slice(0,t)}getFailedAccesses(e,t=24){let n=Date.now()-t*60*60*1000;return Array.from(this.audits.values()).filter((r)=>r.secretId===e&&!r.success&&r.timestamp.getTime()>n)}registerExternalManager(e){let t=`ext-manager-${Date.now()}-${this.managerCounter++}`,n={id:t,...e};return this.externalManagers.set(t,n),n}registerVault(e){return this.registerExternalManager({type:"vault",name:e.name,endpoint:e.endpoint,authentication:{type:e.token?"token":"iam",credentials:e.token?{token:e.token}:void 0,roleArn:e.roleArn},syncEnabled:e.syncEnabled||!1,syncInterval:60})}registerOnePassword(e){return this.registerExternalManager({type:"onepassword",name:e.name,endpoint:e.endpoint||"https://my.1password.com",authentication:{type:"apikey",credentials:{apiKey:e.apiKey}},syncEnabled:e.syncEnabled||!1,syncInterval:30})}enableReplication(e){let t=`replication-${Date.now()}-${this.replicationCounter++}`,n={id:t,secretId:e.secretId,sourceRegion:e.sourceRegion,replicaRegions:e.replicaRegions,kmsKeyIds:e.kmsKeyIds,status:"replicating"};return this.replications.set(t,n),this.auditAction({secretId:e.secretId,action:"REPLICATE",actor:"system",success:!0}),setTimeout(()=>{n.status="completed"},100),n}createPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,n={id:t,secretId:e.secretId,policy:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:e.allowedPrincipals},Action:e.allowedActions,Resource:"*"}]}};return this.policies.set(t,n),n}createCrossAccountPolicy(e){let t=e.roleNames.map((n)=>`arn:aws:iam::${e.accountId}:role/${n}`);return this.createPolicy({secretId:e.secretId,allowedPrincipals:t,allowedActions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"]})}getVersion(e){return this.versions.get(e)}getExternalManager(e){return this.externalManagers.get(e)}listExternalManagers(){return Array.from(this.externalManagers.values())}getReplication(e){return this.replications.get(e)}listReplications(){return Array.from(this.replications.values())}generateSecretCF(e){return{Type:"AWS::SecretsManager::Secret",Properties:{Name:e.name,Description:e.description,...e.kmsKeyId&&{KmsKeyId:e.kmsKeyId},...e.replicaRegions&&{ReplicaRegions:e.replicaRegions.map((t)=>({Region:t}))}}}}generateSecretPolicyCF(e){return{Type:"AWS::SecretsManager::ResourcePolicy",Properties:{SecretId:e.secretId,ResourcePolicy:e.policy}}}clear(){this.versions.clear(),this.audits.clear(),this.externalManagers.clear(),this.replications.clear(),this.policies.clear(),this.versionCounter=0,this.auditCounter=0,this.managerCounter=0,this.replicationCounter=0,this.policyCounter=0}}var Oc=new Pn;class wi{certificates=new Map;renewals=new Map;validations=new Map;monitors=new Map;alerts=new Map;certificateCounter=0;renewalCounter=0;validationCounter=0;monitorCounter=0;alertCounter=0;requestCertificate(e){let t=`cert-${Date.now()}-${this.certificateCounter++}`,n=`arn:aws:acm:us-east-1:123456789012:certificate/${t}`,r={id:t,arn:n,domainName:e.domainName,subjectAlternativeNames:e.subjectAlternativeNames,validationMethod:e.validationMethod||"DNS",status:"PENDING_VALIDATION"};return this.certificates.set(t,r),this.createValidation(r),r}requestWildcardCertificate(e){let t=[];if(e.includeApex)t.push(e.domainName.replace("*.",""));return this.requestCertificate({domainName:e.domainName,subjectAlternativeNames:t.length>0?t:void 0,validationMethod:"DNS"})}requestMultiDomainCertificate(e){return this.requestCertificate({domainName:e.primaryDomain,subjectAlternativeNames:e.additionalDomains,validationMethod:e.validationMethod||"DNS"})}createValidation(e){let t={domainName:e.domainName,validationMethod:e.validationMethod,validationStatus:"PENDING"};if(e.validationMethod==="DNS")t.resourceRecords=[{name:`_${Math.random().toString(36).slice(2)}.${e.domainName}`,type:"CNAME",value:`_${Math.random().toString(36).slice(2)}.acm-validations.aws.`}];else t.validationEmails=[`admin@${e.domainName}`,`administrator@${e.domainName}`,`hostmaster@${e.domainName}`];return this.validations.set(e.id,t),t}validateCertificate(e){let t=this.certificates.get(e),n=this.validations.get(e);if(!t||!n)return{success:!1,message:"Certificate or validation not found"};return n.validationStatus="SUCCESS",t.status="ISSUED",t.issuedAt=new Date,t.expiresAt=new Date(Date.now()+31536000000),t.renewalEligibility=!0,t.issuer="Amazon",{success:!0,message:"Certificate validated and issued successfully"}}enableAutoRenewal(e){let t=`renewal-${Date.now()}-${this.renewalCounter++}`,n={id:t,certificateArn:e.certificateArn,autoRenew:!0,renewBeforeDays:e.renewBeforeDays||30};return this.renewals.set(t,n),n}async renewCertificate(e){let t=this.renewals.get(e);if(!t)return{success:!1,message:"Renewal configuration not found"};let n=Array.from(this.certificates.values()).find((r)=>r.arn===t.certificateArn);if(!n)return{success:!1,message:"Certificate not found"};console.log(`
|
|
3776
3776
|
Renewing certificate: ${n.domainName}`),console.log(`Certificate ARN: ${n.arn}`);try{return console.log(`
|
|
3777
3777
|
1. Requesting new certificate...`),console.log("2. Validating domain ownership..."),console.log("3. Issuing renewed certificate..."),console.log("4. Updating resource associations..."),n.issuedAt=new Date,n.expiresAt=new Date(Date.now()+31536000000),t.lastRenewal=new Date,t.renewalStatus="success",t.nextRenewal=new Date(n.expiresAt.getTime()-t.renewBeforeDays*24*60*60*1000),console.log(`
|
|
3778
|
-
✓ Certificate renewed successfully`),console.log(` New expiration: ${n.expiresAt.toISOString()}`),console.log(` Next renewal: ${t.nextRenewal.toISOString()}`),{success:!0,message:"Certificate renewed successfully"}}catch(r){return t.renewalStatus="failed",this.createAlert({certificateArn:n.arn,alertType:"renewal_failed",severity:"critical",message:`Certificate renewal failed: ${r}`}),{success:!1,message:r instanceof Error?r.message:String(r)}}}createMonitor(e){let t=`monitor-${Date.now()}-${this.monitorCounter++}`,n={id:t,...e};return this.monitors.set(t,n),n}checkExpiration(){let e=[],t=Date.now();for(let n of this.certificates.values()){if(!n.expiresAt)continue;let r=(n.expiresAt.getTime()-t)/86400000;if(r<0)e.push(this.createAlert({certificateArn:n.arn,alertType:"expired",severity:"critical",message:`Certificate has expired for ${n.domainName}`}));else if(r<30)e.push(this.createAlert({certificateArn:n.arn,alertType:"expiring_soon",severity:r<7?"critical":"warning",message:`Certificate expiring in ${Math.floor(r)} days for ${n.domainName}`}))}return e}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)t.acknowledged=!0}getCertificate(e){return this.certificates.get(e)}listCertificates(){return Array.from(this.certificates.values())}getExpiringCertificates(e=30){let t=Date.now()+e*24*60*60*1000;return Array.from(this.certificates.values()).filter((n)=>n.expiresAt&&n.expiresAt.getTime()<t)}getValidation(e){return this.validations.get(e)}getRenewal(e){return this.renewals.get(e)}listRenewals(){return Array.from(this.renewals.values())}listAlerts(e=!1){return Array.from(this.alerts.values()).filter((t)=>t.acknowledged===e)}generateCertificateCF(e){return{Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:e.domainName,...e.subjectAlternativeNames&&{SubjectAlternativeNames:e.subjectAlternativeNames},ValidationMethod:e.validationMethod}}}generateExpirationAlarmCF(e){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`Certificate expiring in ${e.daysBeforeExpiration} days`,MetricName:"DaysToExpiry",Namespace:"AWS/CertificateManager",Statistic:"Minimum",Period:86400,EvaluationPeriods:1,Threshold:e.daysBeforeExpiration,ComparisonOperator:"LessThanThreshold",Dimensions:[{Name:"CertificateArn",Value:e.certificateArn}],...e.snsTopicArn&&{AlarmActions:[e.snsTopicArn]}}}}clear(){this.certificates.clear(),this.renewals.clear(),this.validations.clear(),this.monitors.clear(),this.alerts.clear(),this.certificateCounter=0,this.renewalCounter=0,this.validationCounter=0,this.monitorCounter=0,this.alertCounter=0}}var
|
|
3778
|
+
✓ Certificate renewed successfully`),console.log(` New expiration: ${n.expiresAt.toISOString()}`),console.log(` Next renewal: ${t.nextRenewal.toISOString()}`),{success:!0,message:"Certificate renewed successfully"}}catch(r){return t.renewalStatus="failed",this.createAlert({certificateArn:n.arn,alertType:"renewal_failed",severity:"critical",message:`Certificate renewal failed: ${r}`}),{success:!1,message:r instanceof Error?r.message:String(r)}}}createMonitor(e){let t=`monitor-${Date.now()}-${this.monitorCounter++}`,n={id:t,...e};return this.monitors.set(t,n),n}checkExpiration(){let e=[],t=Date.now();for(let n of this.certificates.values()){if(!n.expiresAt)continue;let r=(n.expiresAt.getTime()-t)/86400000;if(r<0)e.push(this.createAlert({certificateArn:n.arn,alertType:"expired",severity:"critical",message:`Certificate has expired for ${n.domainName}`}));else if(r<30)e.push(this.createAlert({certificateArn:n.arn,alertType:"expiring_soon",severity:r<7?"critical":"warning",message:`Certificate expiring in ${Math.floor(r)} days for ${n.domainName}`}))}return e}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)t.acknowledged=!0}getCertificate(e){return this.certificates.get(e)}listCertificates(){return Array.from(this.certificates.values())}getExpiringCertificates(e=30){let t=Date.now()+e*24*60*60*1000;return Array.from(this.certificates.values()).filter((n)=>n.expiresAt&&n.expiresAt.getTime()<t)}getValidation(e){return this.validations.get(e)}getRenewal(e){return this.renewals.get(e)}listRenewals(){return Array.from(this.renewals.values())}listAlerts(e=!1){return Array.from(this.alerts.values()).filter((t)=>t.acknowledged===e)}generateCertificateCF(e){return{Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:e.domainName,...e.subjectAlternativeNames&&{SubjectAlternativeNames:e.subjectAlternativeNames},ValidationMethod:e.validationMethod}}}generateExpirationAlarmCF(e){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`Certificate expiring in ${e.daysBeforeExpiration} days`,MetricName:"DaysToExpiry",Namespace:"AWS/CertificateManager",Statistic:"Minimum",Period:86400,EvaluationPeriods:1,Threshold:e.daysBeforeExpiration,ComparisonOperator:"LessThanThreshold",Dimensions:[{Name:"CertificateArn",Value:e.certificateArn}],...e.snsTopicArn&&{AlarmActions:[e.snsTopicArn]}}}}clear(){this.certificates.clear(),this.renewals.clear(),this.validations.clear(),this.monitors.clear(),this.alerts.clear(),this.certificateCounter=0,this.renewalCounter=0,this.validationCounter=0,this.monitorCounter=0,this.alertCounter=0}}var Mb=new wi;class Ii{scans=new Map;findings=new Map;reports=new Map;complianceChecks=new Map;postures=new Map;scanCounter=0;findingCounter=0;reportCounter=0;checkCounter=0;postureCounter=0;createScan(e){let t=`scan-${Date.now()}-${this.scanCounter++}`,n={id:t,status:"queued",findings:[],...e};return this.scans.set(t,n),n}createContainerScan(e){return this.createScan({name:e.name,scanType:"container_image",target:{type:"ecr_image",identifier:e.imageUri,region:e.region||"us-east-1"}})}createLambdaScan(e){return this.createScan({name:e.name,scanType:"vulnerability",target:{type:"lambda",identifier:e.functionName,region:e.region||"us-east-1"}})}createSecretsDetectionScan(e){return this.createScan({name:e.name,scanType:"secrets_detection",target:{type:"repository",identifier:e.repositoryUrl}})}async executeScan(e){let t=this.scans.get(e);if(!t)throw Error(`Scan not found: ${e}`);console.log(`
|
|
3779
3779
|
Executing security scan: ${t.name}`),console.log(`Scan type: ${t.scanType}`),console.log(`Target: ${t.target.type} - ${t.target.identifier}`),t.status="running",t.startedAt=new Date;try{console.log(`
|
|
3780
3780
|
Scanning...`);let n=this.simulateFindings(t);return t.findings=n,t.status="completed",t.completedAt=new Date,t.summary={totalFindings:n.length,criticalCount:n.filter((r)=>r.severity==="CRITICAL").length,highCount:n.filter((r)=>r.severity==="HIGH").length,mediumCount:n.filter((r)=>r.severity==="MEDIUM").length,lowCount:n.filter((r)=>r.severity==="LOW").length,infoCount:n.filter((r)=>r.severity==="INFO").length,executionTime:t.completedAt.getTime()-t.startedAt.getTime()},console.log(`
|
|
3781
|
-
✓ Scan completed`),console.log(` Findings: ${t.summary.totalFindings}`),console.log(` Critical: ${t.summary.criticalCount}`),console.log(` High: ${t.summary.highCount}`),console.log(` Medium: ${t.summary.mediumCount}`),console.log(` Low: ${t.summary.lowCount}`),t}catch(n){throw t.status="failed",t.completedAt=new Date,n}}simulateFindings(e){let t=[],n=new Date;if(e.scanType==="container_image")t.push(this.createFinding({severity:"HIGH",title:"Vulnerable OpenSSL version detected",description:"OpenSSL 1.1.1k contains known vulnerabilities",cve:"CVE-2021-3711",cvss:7.5,affectedResource:e.target.identifier,remediation:"Update OpenSSL to version 1.1.1l or later",status:"OPEN",firstDetected:n,lastSeen:n})),t.push(this.createFinding({severity:"MEDIUM",title:"Outdated npm package: lodash",description:"lodash 4.17.19 has known security issues",cve:"CVE-2020-8203",cvss:5.3,affectedResource:e.target.identifier,remediation:"Update lodash to version 4.17.21 or later",status:"OPEN",firstDetected:n,lastSeen:n}));else if(e.scanType==="secrets_detection")t.push(this.createFinding({severity:"CRITICAL",title:"AWS Access Key exposed in code",description:"Hardcoded AWS access key found in source code",affectedResource:`${e.target.identifier}/src/config.ts:12`,remediation:"Remove hardcoded credentials and use AWS Secrets Manager",status:"OPEN",firstDetected:n,lastSeen:n}));return t}createFinding(e){let t=`finding-${Date.now()}-${this.findingCounter++}`,n={id:t,...e};return this.findings.set(t,n),n}suppressFinding(e,t){let n=this.findings.get(e);if(n){if(n.status="SUPPRESSED",console.log(`Finding suppressed: ${n.title}`),t)console.log(`Reason: ${t}`)}}resolveFinding(e){let t=this.findings.get(e);if(t)t.status="RESOLVED",console.log(`Finding resolved: ${t.title}`)}generateReport(e){let t=`report-${Date.now()}-${this.reportCounter++}`,n={id:t,scanId:e.scanId,reportType:e.reportType,format:e.format,generatedAt:new Date,s3Location:`s3://security-reports/${t}.${e.format}`};return this.reports.set(t,n),n}runComplianceCheck(e){let t=[];if(e.framework.includes("CIS"))t.push(this.createComplianceCheck({framework:e.framework,checkId:"1.1",title:"Avoid the use of root account",description:"Root account should not be used for everyday tasks",status:"PASS",severity:"CRITICAL",resourceType:e.resourceType,resourceId:e.resourceId})),t.push(this.createComplianceCheck({framework:e.framework,checkId:"2.1",title:"Ensure CloudTrail is enabled",description:"CloudTrail should be enabled in all regions",status:"FAIL",severity:"HIGH",resourceType:e.resourceType,resourceId:e.resourceId,remediation:"Enable CloudTrail in all regions"}));return t}createComplianceCheck(e){let t=`check-${Date.now()}-${this.checkCounter++}`,n={id:t,...e};return this.complianceChecks.set(t,n),n}assessSecurityPosture(e){let t=`posture-${Date.now()}-${this.postureCounter++}`,n=Array.from(this.complianceChecks.values()),r=n.filter((c)=>c.status==="PASS").length,i=n.length,s=i>0?Math.round(r/i*100):0,a;if(s>=90)a="A";else if(s>=80)a="B";else if(s>=70)a="C";else if(s>=60)a="D";else a="F";let o={id:t,accountId:e.accountId,region:e.region,score:s,grade:a,assessedAt:new Date,strengths:["IAM password policy enforced","Multi-factor authentication enabled","CloudTrail logging enabled"],weaknesses:["Some S3 buckets are publicly accessible","Security groups allow unrestricted ingress","Outdated dependencies in Lambda functions"],recommendations:["Review and update S3 bucket policies","Implement least-privilege security group rules","Update Lambda runtime versions and dependencies","Enable GuardDuty for threat detection"]};return this.postures.set(t,o),o}getScan(e){return this.scans.get(e)}listScans(){return Array.from(this.scans.values())}getOpenFindings(e){return Array.from(this.findings.values()).filter((t)=>t.status==="OPEN"&&(!e||t.severity===e))}getComplianceChecksByStatus(e){return Array.from(this.complianceChecks.values()).filter((t)=>t.status===e)}listPostures(){return Array.from(this.postures.values())}generateECRScanCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e,ImageScanningConfiguration:{ScanOnPush:!0},ImageTagMutability:"IMMUTABLE"}}}clear(){this.scans.clear(),this.findings.clear(),this.reports.clear(),this.complianceChecks.clear(),this.postures.clear(),this.scanCounter=0,this.findingCounter=0,this.reportCounter=0,this.checkCounter=0,this.postureCounter=0}}var
|
|
3781
|
+
✓ Scan completed`),console.log(` Findings: ${t.summary.totalFindings}`),console.log(` Critical: ${t.summary.criticalCount}`),console.log(` High: ${t.summary.highCount}`),console.log(` Medium: ${t.summary.mediumCount}`),console.log(` Low: ${t.summary.lowCount}`),t}catch(n){throw t.status="failed",t.completedAt=new Date,n}}simulateFindings(e){let t=[],n=new Date;if(e.scanType==="container_image")t.push(this.createFinding({severity:"HIGH",title:"Vulnerable OpenSSL version detected",description:"OpenSSL 1.1.1k contains known vulnerabilities",cve:"CVE-2021-3711",cvss:7.5,affectedResource:e.target.identifier,remediation:"Update OpenSSL to version 1.1.1l or later",status:"OPEN",firstDetected:n,lastSeen:n})),t.push(this.createFinding({severity:"MEDIUM",title:"Outdated npm package: lodash",description:"lodash 4.17.19 has known security issues",cve:"CVE-2020-8203",cvss:5.3,affectedResource:e.target.identifier,remediation:"Update lodash to version 4.17.21 or later",status:"OPEN",firstDetected:n,lastSeen:n}));else if(e.scanType==="secrets_detection")t.push(this.createFinding({severity:"CRITICAL",title:"AWS Access Key exposed in code",description:"Hardcoded AWS access key found in source code",affectedResource:`${e.target.identifier}/src/config.ts:12`,remediation:"Remove hardcoded credentials and use AWS Secrets Manager",status:"OPEN",firstDetected:n,lastSeen:n}));return t}createFinding(e){let t=`finding-${Date.now()}-${this.findingCounter++}`,n={id:t,...e};return this.findings.set(t,n),n}suppressFinding(e,t){let n=this.findings.get(e);if(n){if(n.status="SUPPRESSED",console.log(`Finding suppressed: ${n.title}`),t)console.log(`Reason: ${t}`)}}resolveFinding(e){let t=this.findings.get(e);if(t)t.status="RESOLVED",console.log(`Finding resolved: ${t.title}`)}generateReport(e){let t=`report-${Date.now()}-${this.reportCounter++}`,n={id:t,scanId:e.scanId,reportType:e.reportType,format:e.format,generatedAt:new Date,s3Location:`s3://security-reports/${t}.${e.format}`};return this.reports.set(t,n),n}runComplianceCheck(e){let t=[];if(e.framework.includes("CIS"))t.push(this.createComplianceCheck({framework:e.framework,checkId:"1.1",title:"Avoid the use of root account",description:"Root account should not be used for everyday tasks",status:"PASS",severity:"CRITICAL",resourceType:e.resourceType,resourceId:e.resourceId})),t.push(this.createComplianceCheck({framework:e.framework,checkId:"2.1",title:"Ensure CloudTrail is enabled",description:"CloudTrail should be enabled in all regions",status:"FAIL",severity:"HIGH",resourceType:e.resourceType,resourceId:e.resourceId,remediation:"Enable CloudTrail in all regions"}));return t}createComplianceCheck(e){let t=`check-${Date.now()}-${this.checkCounter++}`,n={id:t,...e};return this.complianceChecks.set(t,n),n}assessSecurityPosture(e){let t=`posture-${Date.now()}-${this.postureCounter++}`,n=Array.from(this.complianceChecks.values()),r=n.filter((c)=>c.status==="PASS").length,i=n.length,s=i>0?Math.round(r/i*100):0,a;if(s>=90)a="A";else if(s>=80)a="B";else if(s>=70)a="C";else if(s>=60)a="D";else a="F";let o={id:t,accountId:e.accountId,region:e.region,score:s,grade:a,assessedAt:new Date,strengths:["IAM password policy enforced","Multi-factor authentication enabled","CloudTrail logging enabled"],weaknesses:["Some S3 buckets are publicly accessible","Security groups allow unrestricted ingress","Outdated dependencies in Lambda functions"],recommendations:["Review and update S3 bucket policies","Implement least-privilege security group rules","Update Lambda runtime versions and dependencies","Enable GuardDuty for threat detection"]};return this.postures.set(t,o),o}getScan(e){return this.scans.get(e)}listScans(){return Array.from(this.scans.values())}getOpenFindings(e){return Array.from(this.findings.values()).filter((t)=>t.status==="OPEN"&&(!e||t.severity===e))}getComplianceChecksByStatus(e){return Array.from(this.complianceChecks.values()).filter((t)=>t.status===e)}listPostures(){return Array.from(this.postures.values())}generateECRScanCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e,ImageScanningConfiguration:{ScanOnPush:!0},ImageTagMutability:"IMMUTABLE"}}}clear(){this.scans.clear(),this.findings.clear(),this.reports.clear(),this.complianceChecks.clear(),this.postures.clear(),this.scanCounter=0,this.findingCounter=0,this.reportCounter=0,this.checkCounter=0,this.postureCounter=0}}var Ob=new Ii;class Di{configs=new Map;results=new Map;policies=new Map;configCounter=0;resultCounter=0;policyCounter=0;configureScan(e){let t=`scan-config-${Date.now()}-${this.configCounter++}`,n={id:t,...e};return this.configs.set(t,n),n}configureTrivyScan(e){return this.configureScan({repository:e.repository,imageTag:e.imageTag,scanner:"trivy",scanOnPush:e.scanOnPush??!0,ignoreUnfixed:e.ignoreUnfixed??!1,failOnSeverity:"HIGH"})}configureSnykScan(e){return this.configureScan({repository:e.repository,imageTag:e.imageTag,scanner:"snyk",scanOnPush:e.scanOnPush??!0,failOnSeverity:"HIGH"})}configureECRScan(e){return this.configureScan({repository:e.repository,imageTag:"latest",scanner:"ecr",scanOnPush:e.scanOnPush??!0,failOnSeverity:"CRITICAL"})}async scanImage(e){let t=this.configs.get(e);if(!t)throw Error(`Scan config not found: ${e}`);let n=`${t.repository}:${t.imageTag}`;console.log(`
|
|
3782
3782
|
Scanning image: ${n}`),console.log(`Scanner: ${t.scanner}`);let r=`scan-result-${Date.now()}-${this.resultCounter++}`,i=this.simulateVulnerabilities(t),s={total:i.length,critical:i.filter((c)=>c.severity==="CRITICAL").length,high:i.filter((c)=>c.severity==="HIGH").length,medium:i.filter((c)=>c.severity==="MEDIUM").length,low:i.filter((c)=>c.severity==="LOW").length,unknown:i.filter((c)=>c.severity==="UNKNOWN").length},a=this.evaluateScanResult(t,s),o={id:r,imageUri:n,scannerType:t.scanner,scanDate:new Date,vulnerabilities:i,summary:s,passed:a};return this.results.set(r,o),console.log(`
|
|
3783
|
-
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
|
|
3783
|
+
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 Bb=new Di;class Ni{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(`
|
|
3784
3784
|
`)}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 ./
|
|
3785
3785
|
RUN npm install
|
|
3786
|
-
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 yb=new Ai;class An{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 Cc=new An;class Cn{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 vc=new Cn;class Ci{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 Sb=new Ci;class vi{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 Cb=new vi;class Ti{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 Tb=new Ti;class Ri{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 Pb=new Ri;class Pi{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 wb=new Pi;class Ei{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 Db=new Ei;class vn{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 Tc=new vn;class wi{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 kb=new wi;class Ii{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 Lb=new Ii;class Di{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,p])=>({email:u,count:p})).sort((u,p)=>p.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 $b=new Di;class Ni{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 P=A.timestamp>=e.startDate&&A.timestamp<=e.endDate,R=!e.campaignId||A.tags?.campaignId===e.campaignId;return P&&R}),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,p=i>0?a/i*100:0,m=s>0?a/s*100:0,g=r>0?o/r*100:0,y=i>0?c/i*100:0,f=new Map;for(let A of n)if(A.eventType==="click"){let P=A;f.set(P.link,(f.get(P.link)||0)+1)}let S=Array.from(f.entries()).map(([A,P])=>({link:A,clicks:P})).sort((A,P)=>P.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 P=A.userAgent.toLowerCase();if(P.includes("mobile"))v.mobile++;else if(P.includes("tablet"))v.tablet++;else if(P.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:p,clickToOpenRate:m,bounceRate:g,complaintRate:y,topLinks:S,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 Fb=new Ni;class xi{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 _b=new xi;class ki{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:`
|
|
3786
|
+
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 Gb=new Ni;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 Bc=new wn;class xi{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 Ub=new xi;class ki{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 ki;class Mi{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 qb=new Mi;class Li{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 Qb=new Li;class Oi{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 Yb=new Oi;class $i{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 Xb=new $i;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 Fc=new In;class Bi{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 nS=new Bi;class Fi{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 iS=new Fi;class Gi{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 aS=new Gi;class _i{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 P=A.timestamp>=e.startDate&&A.timestamp<=e.endDate,R=!e.campaignId||A.tags?.campaignId===e.campaignId;return P&&R}),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,f=new Map;for(let A of n)if(A.eventType==="click"){let P=A;f.set(P.link,(f.get(P.link)||0)+1)}let b=Array.from(f.entries()).map(([A,P])=>({link:A,clicks:P})).sort((A,P)=>P.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 P=A.userAgent.toLowerCase();if(P.includes("mobile"))v.mobile++;else if(P.includes("tablet"))v.tablet++;else if(P.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 cS=new _i;class Wi{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 uS=new Wi;class Vi{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:`
|
|
3787
3787
|
<html>
|
|
3788
3788
|
<body>
|
|
3789
3789
|
<h1>Welcome, {{userName}}!</h1>
|
|
@@ -3803,7 +3803,7 @@ COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let o={si
|
|
|
3803
3803
|
<p>If you didn't request this, please ignore this email.</p>
|
|
3804
3804
|
</body>
|
|
3805
3805
|
</html>
|
|
3806
|
-
`,textPart:"Hi {{userName}}, reset your password at: {{resetUrl}}. This link expires in {{expirationHours}} hours."})}updateTemplate(e,t,n){let r=this.templates.get(e);if(!r)throw Error(`Template not found: ${e}`);if(t.subject)r.subject=t.subject;if(t.htmlPart)r.htmlPart=t.htmlPart;if(t.textPart)r.textPart=t.textPart;return r.version++,r.updatedAt=new Date,r.variables=this.extractVariables(r.subject+r.htmlPart+r.textPart),this.addVersion({templateId:e,version:r.version,subject:r.subject,htmlPart:r.htmlPart,textPart:r.textPart,createdBy:"system",changelog:n}),r}addVersion(e){let n={id:`version-${e.templateId}-${e.version}`,createdAt:new Date,...e},r=this.versions.get(e.templateId)||[];return r.push(n),this.versions.set(e.templateId,r),n}extractVariables(e){let t=/\{\{([^}]+)\}\}/g,n=new Set,r;while((r=t.exec(e))!==null)n.add(r[1].trim());return Array.from(n)}renderTemplate(e,t){let n=this.templates.get(e);if(!n)throw Error(`Template not found: ${e}`);let r=(i)=>i.replace(/\{\{([^}]+)\}\}/g,(s,a)=>{let o=a.trim();return t[o]!==void 0?String(t[o]):s});return{subject:r(n.subject),html:r(n.htmlPart),text:r(n.textPart)}}testTemplate(e,t){let n=`test-${Date.now()}-${this.testCounter++}`,r=this.renderTemplate(e,t),i={id:n,templateId:e,testData:t,renderedSubject:r.subject,renderedHtml:r.html,renderedText:r.text,timestamp:new Date};return this.tests.set(n,i),i}getTemplate(e){return this.templates.get(e)}listTemplates(){return Array.from(this.templates.values())}getTemplateVersions(e){return this.versions.get(e)||[]}revertToVersion(e,t){let n=this.templates.get(e);if(!n)throw Error(`Template not found: ${e}`);let i=(this.versions.get(e)||[]).find((s)=>s.version===t);if(!i)throw Error(`Version ${t} not found for template ${e}`);return n.subject=i.subject,n.htmlPart=i.htmlPart,n.textPart=i.textPart,n.version++,n.updatedAt=new Date,this.addVersion({templateId:e,version:n.version,subject:n.subject,htmlPart:n.htmlPart,textPart:n.textPart,createdBy:"system",changelog:`Reverted to version ${t}`}),n}generateTemplateCF(e){return{Type:"AWS::SES::Template",Properties:{Template:{TemplateName:e.name,SubjectPart:e.subject,HtmlPart:e.htmlPart,TextPart:e.textPart}}}}clear(){this.templates.clear(),this.versions.clear(),this.tests.clear(),this.templateCounter=0,this.testCounter=0}}var
|
|
3806
|
+
`,textPart:"Hi {{userName}}, reset your password at: {{resetUrl}}. This link expires in {{expirationHours}} hours."})}updateTemplate(e,t,n){let r=this.templates.get(e);if(!r)throw Error(`Template not found: ${e}`);if(t.subject)r.subject=t.subject;if(t.htmlPart)r.htmlPart=t.htmlPart;if(t.textPart)r.textPart=t.textPart;return r.version++,r.updatedAt=new Date,r.variables=this.extractVariables(r.subject+r.htmlPart+r.textPart),this.addVersion({templateId:e,version:r.version,subject:r.subject,htmlPart:r.htmlPart,textPart:r.textPart,createdBy:"system",changelog:n}),r}addVersion(e){let n={id:`version-${e.templateId}-${e.version}`,createdAt:new Date,...e},r=this.versions.get(e.templateId)||[];return r.push(n),this.versions.set(e.templateId,r),n}extractVariables(e){let t=/\{\{([^}]+)\}\}/g,n=new Set,r;while((r=t.exec(e))!==null)n.add(r[1].trim());return Array.from(n)}renderTemplate(e,t){let n=this.templates.get(e);if(!n)throw Error(`Template not found: ${e}`);let r=(i)=>i.replace(/\{\{([^}]+)\}\}/g,(s,a)=>{let o=a.trim();return t[o]!==void 0?String(t[o]):s});return{subject:r(n.subject),html:r(n.htmlPart),text:r(n.textPart)}}testTemplate(e,t){let n=`test-${Date.now()}-${this.testCounter++}`,r=this.renderTemplate(e,t),i={id:n,templateId:e,testData:t,renderedSubject:r.subject,renderedHtml:r.html,renderedText:r.text,timestamp:new Date};return this.tests.set(n,i),i}getTemplate(e){return this.templates.get(e)}listTemplates(){return Array.from(this.templates.values())}getTemplateVersions(e){return this.versions.get(e)||[]}revertToVersion(e,t){let n=this.templates.get(e);if(!n)throw Error(`Template not found: ${e}`);let i=(this.versions.get(e)||[]).find((s)=>s.version===t);if(!i)throw Error(`Version ${t} not found for template ${e}`);return n.subject=i.subject,n.htmlPart=i.htmlPart,n.textPart=i.textPart,n.version++,n.updatedAt=new Date,this.addVersion({templateId:e,version:n.version,subject:n.subject,htmlPart:n.htmlPart,textPart:n.textPart,createdBy:"system",changelog:`Reverted to version ${t}`}),n}generateTemplateCF(e){return{Type:"AWS::SES::Template",Properties:{Template:{TemplateName:e.name,SubjectPart:e.subject,HtmlPart:e.htmlPart,TextPart:e.textPart}}}}clear(){this.templates.clear(),this.versions.clear(),this.tests.clear(),this.templateCounter=0,this.testCounter=0}}var mS=new Vi;var Ui={};Oe(Ui,{EmailAnalyticsModule:()=>pt,EmailRules:()=>Mn,EmailScheduling:()=>xn,EmailSearch:()=>Dn,EmailTemplates:()=>ke,EmailThreading:()=>Nn,SharedMailboxes:()=>kn});class Dn{static createSearchDomain(e){let{slug:t,environment:n,domainName:r,instanceType:i="t3.small.search",instanceCount:s=1,ebsVolumeSize:a=10,masterUserName:o="admin",masterUserPassword:c}=e,l=r||`${t}-${n}-email-search`;return{[`${t}EmailSearchDomain`]:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:l,EngineVersion:"OpenSearch_2.11",ClusterConfig:{InstanceType:i,InstanceCount:s,DedicatedMasterEnabled:!1,ZoneAwarenessEnabled:!1},EBSOptions:{EBSEnabled:!0,VolumeType:"gp3",VolumeSize:a},NodeToNodeEncryptionOptions:{Enabled:!0},EncryptionAtRestOptions:{Enabled:!0},DomainEndpointOptions:{EnforceHTTPS:!0},AdvancedSecurityOptions:{Enabled:!0,InternalUserDatabaseEnabled:!0,MasterUserOptions:{MasterUserName:o,MasterUserPassword:c||`${t}-search-${Date.now()}`}},AccessPolicies:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:`arn:aws:es:*:*:domain/${l}/*`}]}}}}}static createIndexerLambda(e){return{[`${e.slug}EmailIndexerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-indexer`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:512,Code:{ZipFile:Dn.IndexerLambdaCode},Environment:{Variables:{OPENSEARCH_ENDPOINT:e.searchDomainEndpoint,EMAIL_BUCKET:e.emailBucket}}}}}}static IndexerLambdaCode=`
|
|
3807
3807
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
3808
3808
|
const https = require('https');
|
|
3809
3809
|
|
|
@@ -3903,7 +3903,7 @@ async function indexDocument(doc) {
|
|
|
3903
3903
|
req.end();
|
|
3904
3904
|
});
|
|
3905
3905
|
}
|
|
3906
|
-
`;static getIndexMapping(){return{mappings:{properties:{messageId:{type:"keyword"},from:{type:"keyword"},fromName:{type:"text"},to:{type:"keyword"},toName:{type:"text"},cc:{type:"keyword"},subject:{type:"text",analyzer:"standard",fields:{keyword:{type:"keyword"}}},body:{type:"text",analyzer:"standard"},bodyPreview:{type:"text"},date:{type:"date"},receivedAt:{type:"date"},hasAttachments:{type:"boolean"},attachmentNames:{type:"keyword"},labels:{type:"keyword"},folder:{type:"keyword"},threadId:{type:"keyword"},isRead:{type:"boolean"},isStarred:{type:"boolean"},mailbox:{type:"keyword"}}},settings:{number_of_shards:1,number_of_replicas:0}}}static buildSearchQuery(e){let t=[],n=[];if(e.query)t.push({multi_match:{query:e.query,fields:["subject^3","body","fromName","toName"],type:"best_fields",fuzziness:"AUTO"}});if(e.from)n.push({term:{from:e.from}});if(e.to)n.push({term:{to:e.to}});if(e.subject)t.push({match_phrase:{subject:e.subject}});if(e.hasAttachments!==void 0)n.push({term:{hasAttachments:e.hasAttachments}});if(e.folder)n.push({term:{folder:e.folder}});if(e.labels&&e.labels.length>0)n.push({terms:{labels:e.labels}});if(e.isRead!==void 0)n.push({term:{isRead:e.isRead}});if(e.dateFrom||e.dateTo){let s={date:{}};if(e.dateFrom)s.date.gte=e.dateFrom;if(e.dateTo)s.date.lte=e.dateTo;n.push({range:s})}let r={bool:{}};if(t.length>0)r.bool.must=t;if(n.length>0)r.bool.filter=n;if(t.length===0&&n.length===0)r.bool.must=[{match_all:{}}];let i=[];if(e.sort==="relevance"&&e.query)i.push({_score:e.sortOrder||"desc"});return i.push({date:e.sortOrder||"desc"}),{query:r,sort:i,from:e.offset||0,size:e.limit||20,highlight:{fields:{subject:{},body:{fragment_size:150,number_of_fragments:3}}}}}}class
|
|
3906
|
+
`;static getIndexMapping(){return{mappings:{properties:{messageId:{type:"keyword"},from:{type:"keyword"},fromName:{type:"text"},to:{type:"keyword"},toName:{type:"text"},cc:{type:"keyword"},subject:{type:"text",analyzer:"standard",fields:{keyword:{type:"keyword"}}},body:{type:"text",analyzer:"standard"},bodyPreview:{type:"text"},date:{type:"date"},receivedAt:{type:"date"},hasAttachments:{type:"boolean"},attachmentNames:{type:"keyword"},labels:{type:"keyword"},folder:{type:"keyword"},threadId:{type:"keyword"},isRead:{type:"boolean"},isStarred:{type:"boolean"},mailbox:{type:"keyword"}}},settings:{number_of_shards:1,number_of_replicas:0}}}static buildSearchQuery(e){let t=[],n=[];if(e.query)t.push({multi_match:{query:e.query,fields:["subject^3","body","fromName","toName"],type:"best_fields",fuzziness:"AUTO"}});if(e.from)n.push({term:{from:e.from}});if(e.to)n.push({term:{to:e.to}});if(e.subject)t.push({match_phrase:{subject:e.subject}});if(e.hasAttachments!==void 0)n.push({term:{hasAttachments:e.hasAttachments}});if(e.folder)n.push({term:{folder:e.folder}});if(e.labels&&e.labels.length>0)n.push({terms:{labels:e.labels}});if(e.isRead!==void 0)n.push({term:{isRead:e.isRead}});if(e.dateFrom||e.dateTo){let s={date:{}};if(e.dateFrom)s.date.gte=e.dateFrom;if(e.dateTo)s.date.lte=e.dateTo;n.push({range:s})}let r={bool:{}};if(t.length>0)r.bool.must=t;if(n.length>0)r.bool.filter=n;if(t.length===0&&n.length===0)r.bool.must=[{match_all:{}}];let i=[];if(e.sort==="relevance"&&e.query)i.push({_score:e.sortOrder||"desc"});return i.push({date:e.sortOrder||"desc"}),{query:r,sort:i,from:e.offset||0,size:e.limit||20,highlight:{fields:{subject:{},body:{fragment_size:150,number_of_fragments:3}}}}}}class Nn{static ThreadingLambdaCode=`
|
|
3907
3907
|
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
3908
3908
|
const crypto = require('crypto');
|
|
3909
3909
|
|
|
@@ -4043,7 +4043,7 @@ catch {
|
|
|
4043
4043
|
ContentType: 'application/json',
|
|
4044
4044
|
}));
|
|
4045
4045
|
}
|
|
4046
|
-
`;static createThreadingLambda(e){return{[`${e.slug}EmailThreadingLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:
|
|
4046
|
+
`;static createThreadingLambda(e){return{[`${e.slug}EmailThreadingLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:Nn.ThreadingLambdaCode},Environment:{Variables:{EMAIL_BUCKET:e.emailBucket}}}}}}static async getThreads(e){let{s3Client:t,bucket:n,mailbox:r,limit:i=50,offset:s=0}=e,[a,o]=r.includes("@")?r.split("@"):[r,"default"],c=`mailboxes/${o}/${a}/threads.json`;try{let l=await t.send({Bucket:n,Key:c}),u=JSON.parse(l.Body),m=Object.values(u);return m.sort((p,g)=>new Date(g.lastMessageDate).getTime()-new Date(p.lastMessageDate).getTime()),m.slice(s,s+i)}catch{return[]}}static async getThread(e){let{s3Client:t,bucket:n,mailbox:r,threadId:i}=e,[s,a]=r.includes("@")?r.split("@"):[r,"default"],o=`mailboxes/${a}/${s}/threads.json`;try{let c=await t.send({Bucket:n,Key:o});return JSON.parse(c.Body)[i]||null}catch{return null}}}class xn{static SchedulerLambdaCode=`
|
|
4047
4047
|
const { S3Client, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, ListObjectsV2Command } = require('@aws-sdk/client-s3');
|
|
4048
4048
|
const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
|
|
4049
4049
|
|
|
@@ -4172,7 +4172,7 @@ else {
|
|
|
4172
4172
|
|
|
4173
4173
|
return raw;
|
|
4174
4174
|
}
|
|
4175
|
-
`;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:
|
|
4175
|
+
`;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=`
|
|
4176
4176
|
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
4177
4177
|
|
|
4178
4178
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -4375,7 +4375,7 @@ catch (error) {
|
|
|
4375
4375
|
|
|
4376
4376
|
return { statusCode: 200 };
|
|
4377
4377
|
};
|
|
4378
|
-
`;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:
|
|
4378
|
+
`;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=`
|
|
4379
4379
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
4380
4380
|
|
|
4381
4381
|
const s3 = new S3Client({});
|
|
@@ -4630,7 +4630,7 @@ The {{appName}} Team`,variables:["appName","userName","resetUrl","expiresIn"],ca
|
|
|
4630
4630
|
|
|
4631
4631
|
<p>Best regards,<br>The {{appName}} Team</p>
|
|
4632
4632
|
</body>
|
|
4633
|
-
</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:
|
|
4633
|
+
</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=`
|
|
4634
4634
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
4635
4635
|
const { DynamoDBClient, GetItemCommand, PutItemCommand, QueryCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
4636
4636
|
|
|
@@ -4861,7 +4861,7 @@ function unmarshallMailbox(item) {
|
|
|
4861
4861
|
updatedAt: item.updatedAt.S,
|
|
4862
4862
|
};
|
|
4863
4863
|
}
|
|
4864
|
-
`;static createMailboxTable(e){return{[`${e.slug}SharedMailboxTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-shared-mailboxes`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"},{AttributeName:"type",AttributeType:"S"},{AttributeName:"mailboxId",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"type-index",KeySchema:[{AttributeName:"type",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}},{IndexName:"mailbox-index",KeySchema:[{AttributeName:"mailboxId",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}],Projection:{ProjectionType:"ALL"}}]}}}}static createSharedMailboxLambda(e){return{[`${e.slug}SharedMailboxLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-shared-mailbox`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:
|
|
4864
|
+
`;static createMailboxTable(e){return{[`${e.slug}SharedMailboxTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-shared-mailboxes`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"},{AttributeName:"type",AttributeType:"S"},{AttributeName:"mailboxId",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"type-index",KeySchema:[{AttributeName:"type",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}},{IndexName:"mailbox-index",KeySchema:[{AttributeName:"mailboxId",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}],Projection:{ProjectionType:"ALL"}}]}}}}static createSharedMailboxLambda(e){return{[`${e.slug}SharedMailboxLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-shared-mailbox`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:kn.SharedMailboxLambdaCode},Environment:{Variables:{EMAIL_BUCKET:e.emailBucket,MAILBOX_TABLE:e.mailboxTable}}}}}}static PermissionSets={owner:{read:!0,send:!0,delete:!0,manage:!0,assignTo:!0},admin:{read:!0,send:!0,delete:!0,manage:!0,assignTo:!0},member:{read:!0,send:!0,delete:!1,manage:!1,assignTo:!0},viewer:{read:!0,send:!1,delete:!1,manage:!1,assignTo:!1}}}class Mn{static RuleProcessorCode=`
|
|
4865
4865
|
const { S3Client, GetObjectCommand, PutObjectCommand, CopyObjectCommand, DeleteObjectCommand } = require('@aws-sdk/client-s3');
|
|
4866
4866
|
const { DynamoDBClient, QueryCommand } = require('@aws-sdk/client-dynamodb');
|
|
4867
4867
|
const { LambdaClient, InvokeCommand } = require('@aws-sdk/client-lambda');
|
|
@@ -5174,7 +5174,7 @@ async function invokeLambda(functionName, metadata) {
|
|
|
5174
5174
|
Payload: JSON.stringify(metadata),
|
|
5175
5175
|
}));
|
|
5176
5176
|
}
|
|
5177
|
-
`;static createRulesTable(e){return{[`${e.slug}EmailRulesTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-email-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"mailbox",AttributeType:"S"},{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"mailbox",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}]}}}}static createRuleProcessorLambda(e){return{[`${e.slug}EmailRuleProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-rule-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:
|
|
5177
|
+
`;static createRulesTable(e){return{[`${e.slug}EmailRulesTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-email-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"mailbox",AttributeType:"S"},{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"mailbox",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}]}}}}static createRuleProcessorLambda(e){return{[`${e.slug}EmailRuleProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-rule-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:Mn.RuleProcessorCode},Environment:{Variables:{EMAIL_BUCKET:e.emailBucket,RULES_TABLE:e.rulesTable}}}}}}static RuleTemplates={spamFilter:{name:"Spam Filter",conditions:[{field:"subject",operator:"regex",value:"(viagra|lottery|winner|prince|inheritance)",caseSensitive:!1}],conditionOperator:"or",actions:[{type:"move",params:{folder:"spam"}},{type:"mark-read",params:{}}]},autoLabel:{name:"Auto Label Invoices",conditions:[{field:"subject",operator:"contains",value:"invoice",caseSensitive:!1}],conditionOperator:"and",actions:[{type:"label",params:{label:"invoices"}}]},forwardUrgent:{name:"Forward Urgent",conditions:[{field:"subject",operator:"contains",value:"urgent",caseSensitive:!1}],conditionOperator:"and",actions:[{type:"forward",params:{to:"admin@example.com"}},{type:"label",params:{label:"urgent"}}]}}}var Hi={};Oe(Hi,{default:()=>_c,handler:()=>Gc});var Gc=`
|
|
5178
5178
|
const { S3Client, GetObjectCommand, PutObjectCommand, CopyObjectCommand } = require('@aws-sdk/client-s3');
|
|
5179
5179
|
const s3 = new S3Client({});
|
|
5180
5180
|
|
|
@@ -5332,7 +5332,7 @@ catch (error) {
|
|
|
5332
5332
|
|
|
5333
5333
|
return { statusCode: 200, body: 'OK' };
|
|
5334
5334
|
};
|
|
5335
|
-
`,
|
|
5335
|
+
`,_c=`
|
|
5336
5336
|
const { S3Client, GetObjectCommand, PutObjectCommand, CopyObjectCommand } = require('@aws-sdk/client-s3');
|
|
5337
5337
|
const s3 = new S3Client({});
|
|
5338
5338
|
|
|
@@ -5490,7 +5490,7 @@ catch (error) {
|
|
|
5490
5490
|
|
|
5491
5491
|
return { statusCode: 200, body: 'OK' };
|
|
5492
5492
|
};
|
|
5493
|
-
`;var
|
|
5493
|
+
`;var ji={};Oe(ji,{CallAnalytics:()=>On,CallRecording:()=>Ln,Callbacks:()=>xt,IVRBuilder:()=>He});class Ln{static RecordingProcessorCode=`
|
|
5494
5494
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
5495
5495
|
const { TranscribeClient, StartTranscriptionJobCommand } = require('@aws-sdk/client-transcribe');
|
|
5496
5496
|
const { DynamoDBClient, PutItemCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
@@ -5682,7 +5682,7 @@ else if (jobStatus === 'FAILED') {
|
|
|
5682
5682
|
|
|
5683
5683
|
return { statusCode: 200 };
|
|
5684
5684
|
};
|
|
5685
|
-
`;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:
|
|
5685
|
+
`;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=`
|
|
5686
5686
|
const { DynamoDBClient, PutItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
|
|
5687
5687
|
|
|
5688
5688
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -5881,7 +5881,7 @@ catch (error) {
|
|
|
5881
5881
|
};
|
|
5882
5882
|
}
|
|
5883
5883
|
};
|
|
5884
|
-
`;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:
|
|
5884
|
+
`;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=`
|
|
5885
5885
|
const { DynamoDBClient, PutItemCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
5886
5886
|
const { ConnectClient, StartOutboundVoiceContactCommand } = require('@aws-sdk/client-connect');
|
|
5887
5887
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
@@ -6171,7 +6171,7 @@ catch (error) {
|
|
|
6171
6171
|
return { statusCode: 500, error: error.message };
|
|
6172
6172
|
}
|
|
6173
6173
|
};
|
|
6174
|
-
`;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:
|
|
6174
|
+
`;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||""}}}}}}}var Ki={};Oe(Ki,{AbTesting:()=>Te,LinkTracking:()=>_n,MmsSupport:()=>Fn,SmsAnalytics:()=>Bn,SmsCampaigns:()=>$n,SmsChatbot:()=>Gn});class $n{static CampaignManagerCode=`
|
|
6175
6175
|
const { DynamoDBClient, PutItemCommand, GetItemCommand, UpdateItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
|
|
6176
6176
|
|
|
6177
6177
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -6555,7 +6555,7 @@ function unmarshallCampaign(item) {
|
|
|
6555
6555
|
stats: JSON.parse(item.stats?.S || '{}'),
|
|
6556
6556
|
};
|
|
6557
6557
|
}
|
|
6558
|
-
`;static createCampaignsTable(e){return{[`${e.slug}SmsCampaignsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createCampaignManagerLambda(e){return{[`${e.slug}SmsCampaignManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-campaign-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile
|
|
6558
|
+
`;static createCampaignsTable(e){return{[`${e.slug}SmsCampaignsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createCampaignManagerLambda(e){return{[`${e.slug}SmsCampaignManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-campaign-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:$n.CampaignManagerCode},Environment:{Variables:{CAMPAIGNS_TABLE:e.campaignsTable}}}}}}}class Bn{static AnalyticsAggregatorCode=`
|
|
6559
6559
|
const { DynamoDBClient, ScanCommand, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
6560
6560
|
|
|
6561
6561
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -6750,7 +6750,7 @@ catch (error) {
|
|
|
6750
6750
|
|
|
6751
6751
|
return { statusCode: 200 };
|
|
6752
6752
|
};
|
|
6753
|
-
`;static createAnalyticsTable(e){return{[`${e.slug}SmsAnalyticsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createDeliveryReportsTable(e){return{[`${e.slug}SmsDeliveryReportsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-delivery-reports`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createAnalyticsAggregatorLambda(e){return{[`${e.slug}SmsAnalyticsAggregatorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-analytics-aggregator`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:
|
|
6753
|
+
`;static createAnalyticsTable(e){return{[`${e.slug}SmsAnalyticsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createDeliveryReportsTable(e){return{[`${e.slug}SmsDeliveryReportsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-delivery-reports`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createAnalyticsAggregatorLambda(e){return{[`${e.slug}SmsAnalyticsAggregatorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-analytics-aggregator`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:Bn.AnalyticsAggregatorCode},Environment:{Variables:{MESSAGE_LOG_TABLE:e.messageLogTable,ANALYTICS_TABLE:e.analyticsTable}}}}}}}class Fn{static MmsSenderCode=`
|
|
6754
6754
|
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
6755
6755
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
6756
6756
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
@@ -6942,8 +6942,8 @@ async function sendFallbackSms(to, message) {
|
|
|
6942
6942
|
fallback: true,
|
|
6943
6943
|
};
|
|
6944
6944
|
}
|
|
6945
|
-
`;static createMediaBucket(e){return{[`${e.slug}MmsMediaBucket`]:{Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]},CorsConfiguration:{CorsRules:[{AllowedOrigins:["*"],AllowedMethods:["GET"],AllowedHeaders:["*"],MaxAge:3600}]}}}}}static createMmsSenderLambda(e){return{[`${e.slug}MmsSenderLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-mms-sender`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:512,Code:{ZipFile:
|
|
6946
|
-
`);static createSessionsTable(e){return{[`${e.slug}ChatbotSessionsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createRulesTable(e){return{[`${e.slug}ChatbotRulesTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createChatbotProcessorLambda(e){return{[`${e.slug}ChatbotProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-chatbot-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:
|
|
6945
|
+
`;static createMediaBucket(e){return{[`${e.slug}MmsMediaBucket`]:{Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]},CorsConfiguration:{CorsRules:[{AllowedOrigins:["*"],AllowedMethods:["GET"],AllowedHeaders:["*"],MaxAge:3600}]}}}}}static createMmsSenderLambda(e){return{[`${e.slug}MmsSenderLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-mms-sender`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:512,Code:{ZipFile:Fn.MmsSenderCode},Environment:{Variables:{MEDIA_BUCKET:e.mediaBucket,MESSAGE_LOG_TABLE:e.messageLogTable,ORIGINATION_NUMBER:e.originationNumber||""}}}}}}static SupportedMediaTypes={image:["image/jpeg","image/png","image/gif"],video:["video/mp4","video/3gpp"],audio:["audio/mpeg","audio/wav"]};static MediaSizeLimits={image:1048576,video:5242880,audio:1048576}}class Gn{static ChatbotProcessorCode=["const { DynamoDBClient, GetItemCommand, PutItemCommand, UpdateItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');","const { BedrockRuntimeClient, InvokeModelCommand } = require('@aws-sdk/client-bedrock-runtime');","const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');","","const dynamodb = new DynamoDBClient({});","const bedrock = new BedrockRuntimeClient({});","const sns = new SNSClient({});","","const SESSIONS_TABLE = process.env.SESSIONS_TABLE;","const RULES_TABLE = process.env.RULES_TABLE;","const CHATBOT_CONFIG = JSON.parse(process.env.CHATBOT_CONFIG || '{}');","","exports.handler = async (event) => {"," console.log('Chatbot event:', JSON.stringify(event, null, 2));"," for (const record of event.Records) {"," try {"," const message = JSON.parse(record.Sns?.Message || record.body || '{}');"," const { originationNumber, messageBody } = message;"," if (!originationNumber || !messageBody) continue;"," const response = await processMessage(originationNumber, messageBody.trim());"," await sendResponse(originationNumber, response);"," } catch (error) {"," console.error('Error:', error);"," }"," }"," return { statusCode: 200 };","};","","async function processMessage(phoneNumber, message) {"," const rules = await getRules();"," const lowerMessage = message.toLowerCase();"," for (const rule of rules) {"," for (const pattern of rule.patterns) {"," if (new RegExp(pattern, 'i').test(lowerMessage)) {"," return rule.response;"," }"," }"," }"," return CHATBOT_CONFIG.fallbackMessage || 'Sorry, I did not understand. Please try again.';","}","","async function getRules() {"," const result = await dynamodb.send(new ScanCommand({ TableName: RULES_TABLE }));"," return (result.Items || []).map(item => ({"," patterns: JSON.parse(item.patterns?.S || '[]'),"," response: item.response?.S || '',"," })).sort((a, b) => (a.priority || 0) - (b.priority || 0));","}","","async function sendResponse(phoneNumber, message) {"," await sns.send(new PublishCommand({"," PhoneNumber: phoneNumber,"," Message: message.substring(0, 1600),"," MessageAttributes: {"," 'AWS.SNS.SMS.SMSType': { DataType: 'String', StringValue: 'Transactional' },"," },"," }));","}"].join(`
|
|
6946
|
+
`);static createSessionsTable(e){return{[`${e.slug}ChatbotSessionsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createRulesTable(e){return{[`${e.slug}ChatbotRulesTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createChatbotProcessorLambda(e){return{[`${e.slug}ChatbotProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-chatbot-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Gn.ChatbotProcessorCode},Environment:{Variables:{SESSIONS_TABLE:e.sessionsTable,RULES_TABLE:e.rulesTable,CHATBOT_CONFIG:JSON.stringify(e.chatbotConfig),ORIGINATION_NUMBER:e.originationNumber||""}}}}}}static DefaultRules=[{id:"greeting",priority:1,patterns:["^(hi|hello|hey|howdy)$","^good (morning|afternoon|evening)"],response:"Hello! How can I help you today?"},{id:"help",priority:2,patterns:["^help$","what can you do","how does this work"],response:"I can help with: 1) Account info 2) Support 3) Hours. Reply with a number."},{id:"hours",priority:3,patterns:["hours","open","when are you"],response:"We are open Mon-Fri 9am-5pm EST. Closed weekends."},{id:"thanks",priority:4,patterns:["^(thanks|thank you|thx)"],response:"You're welcome! Is there anything else I can help with?"},{id:"bye",priority:5,patterns:["^(bye|goodbye|quit|exit|stop)$"],response:"Goodbye! Text us anytime if you need help.",action:"end"}]}class _n{static LinkShortenerCode=`
|
|
6947
6947
|
const { DynamoDBClient, PutItemCommand, GetItemCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
6948
6948
|
const crypto = require('crypto');
|
|
6949
6949
|
|
|
@@ -7077,7 +7077,7 @@ function generateShortId() {
|
|
|
7077
7077
|
}
|
|
7078
7078
|
return id;
|
|
7079
7079
|
}
|
|
7080
|
-
`;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:
|
|
7080
|
+
`;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=`
|
|
7081
7081
|
const { DynamoDBClient, PutItemCommand, GetItemCommand, UpdateItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
|
|
7082
7082
|
|
|
7083
7083
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -7271,7 +7271,7 @@ function unmarshallTest(item) {
|
|
|
7271
7271
|
|
|
7272
7272
|
return test;
|
|
7273
7273
|
}
|
|
7274
|
-
`;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:ve.AbTestManagerCode},Environment:{Variables:{AB_TESTS_TABLE:e.abTestsTable}}}}}}static selectVariant(e,t){let r=ve.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=ve.getMetricValue(n,t);for(let i of e.variants.slice(1)){let s=ve.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=ve.getMetricValue(e,n)/100,a=ve.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 Bi{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 xS=new Bi;class Fi{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,p)=>u+p.messagesReceived,0),a=r.reduce((u,p)=>u+p.messagesDeleted,0),o=r.reduce((u,p)=>u+p.messagesReprocessed,0),c=r.reduce((u,p)=>u+p.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 MS=new Fi;class Gi{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((p)=>p.status==="success").map((p)=>p.processingTime||0).filter((p)=>p>0),s=i.length>0?i.reduce((p,m)=>p+m,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 OS=new Gi;class _i{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 BS=new _i;import{deflateRawSync as Ec}from"node:zlib";var wc=(()=>{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 Ic(e){let t=4294967295;for(let n=0;n<e.length;n++)t=wc[(t^e[n])&255]^t>>>8;return(t^4294967295)>>>0}function Dc(e){if(typeof e==="string")return Buffer.from(e,"utf-8");if(Buffer.isBuffer(e))return e;return Buffer.from(e)}function Nc(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=Dc(a.data),c=Ec(o),l=Ic(o),u=Buffer.from(a.name.replace(/\\/g,"/"),"utf-8"),{time:p,date:m}=Nc(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(p,10),y.writeUInt16LE(m,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 f=Buffer.alloc(46+u.length);f.writeUInt32LE(33639248,0),f.writeUInt16LE(798,4),f.writeUInt16LE(20,6),f.writeUInt16LE(0,8),f.writeUInt16LE(8,10),f.writeUInt16LE(p,12),f.writeUInt16LE(m,14),f.writeUInt32LE(l,16),f.writeUInt32LE(c.length,20),f.writeUInt32LE(o.length,24),f.writeUInt16LE(u.length,28),f.writeUInt16LE(0,30),f.writeUInt16LE(0,32),f.writeUInt16LE(0,34),f.writeUInt16LE(0,36),f.writeUInt32LE((g&65535)<<16,38),f.writeUInt32LE(r,42),u.copy(f,46),t.push(y,c),n.push(f),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 Wi(e){let t=e.adapterImport??"./adapter",n=e.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
|
|
7274
|
+
`;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 qi{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 tA=new qi;class zi{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 rA=new zi;class Qi{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 sA=new Qi;class Ji{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 oA=new Ji;import{deflateRawSync as Wc}from"node:zlib";var Vc=(()=>{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 Uc(e){let t=4294967295;for(let n=0;n<e.length;n++)t=Vc[(t^e[n])&255]^t>>>8;return(t^4294967295)>>>0}function Hc(e){if(typeof e==="string")return Buffer.from(e,"utf-8");if(Buffer.isBuffer(e))return e;return Buffer.from(e)}function jc(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 fe(e){let t=[],n=[],r=0;for(let a of e){let o=Hc(a.data),c=Wc(o),l=Uc(o),u=Buffer.from(a.name.replace(/\\/g,"/"),"utf-8"),{time:m,date:p}=jc(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 f=Buffer.alloc(46+u.length);f.writeUInt32LE(33639248,0),f.writeUInt16LE(798,4),f.writeUInt16LE(20,6),f.writeUInt16LE(0,8),f.writeUInt16LE(8,10),f.writeUInt16LE(m,12),f.writeUInt16LE(p,14),f.writeUInt32LE(l,16),f.writeUInt32LE(c.length,20),f.writeUInt32LE(o.length,24),f.writeUInt16LE(u.length,28),f.writeUInt16LE(0,30),f.writeUInt16LE(0,32),f.writeUInt16LE(0,34),f.writeUInt16LE(0,36),f.writeUInt32LE((g&65535)<<16,38),f.writeUInt32LE(r,42),u.copy(f,46),t.push(y,c),n.push(f),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 Yi(e){let t=e.adapterImport??"./adapter",n=e.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
|
|
7275
7275
|
import * as __userModule from ${JSON.stringify(n)}
|
|
7276
7276
|
import { resolveApp, createHandlers } from ${JSON.stringify(t)}
|
|
7277
7277
|
|
|
@@ -7281,9 +7281,9 @@ const __handlers = createHandlers(__app)
|
|
|
7281
7281
|
export const http = __handlers.http
|
|
7282
7282
|
export const queue = __handlers.queue
|
|
7283
7283
|
export const cli = __handlers.cli
|
|
7284
|
-
`}import{execSync as
|
|
7284
|
+
`}import{execSync as Kc}from"node:child_process";import{createHash as qc}from"node:crypto";import{cpSync as zc,mkdtempSync as Qc,rmSync as Jc,writeFileSync as Yc}from"node:fs";import{tmpdir as Zc}from"node:os";import{dirname as Xc,isAbsolute as el,join as je,resolve as tl}from"node:path";import{fileURLToPath as nl}from"node:url";var rl=["adapter.ts","recursion.ts","auto-recursion.ts"];function il(){return je(Xc(nl(import.meta.url)),"runtime")}function sl(e,t,n){for(let r of e??[])n?.(`build: ${r}`),Kc(r,{stdio:"inherit",cwd:t})}function al(e){return qc("sha256").update(e).digest("hex")}function PA(e,t,n){return`deployments/${e}/${t}/${n}.zip`}async function EA(e){let t=tl(e.projectRoot??process.cwd()),{app:n}=e;if(!e.skipBuild)sl(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=el(r)?r:je(t,r),s=Qc(je(Zc(),"tscloud-pkg-"));try{for(let p of rl)zc(je(il(),p),je(s,p));let a=je(s,"bootstrap.ts");Yc(a,Yi({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(`
|
|
7285
7285
|
`);throw Error(`serverless app bundle failed:
|
|
7286
|
-
${m}`)}let c=o.outputs[0],l=Buffer.from(await c.arrayBuffer()),u="index",p=he([{name:`${u}.mjs`,data:l}]);return{zip:p,bundle:l,sha256:jc(p),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{Oc(s,{recursive:!0,force:!0})}}var Kc=["18","20","22"];function qc(e){if(!e)return"22";let t=String(e).match(/(\d+)/);return t?t[1]:"22"}function Vi(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=qc(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&Kc.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 Ui(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 cA(e,t,n){return Ui(e,t,n).map((r)=>r.name)}function lA(e){let{app:t,environment:n,handlers:r}=e,i=e.config.project.slug,s=Vi(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=Ui(t,i,n),u=l.map((I)=>I.name),p=u.length>0,m=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",f=(t.cache?.driver??"dynamodb")==="dynamodb",S=Boolean(t.assets),v=qn(i,n),T=t.tmpStorage??512,A={},P={},R=[{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(p)R[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(f)R[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:R}};let D=(I)=>({TSCLOUD_LAMBDA_MODE:I,TSCLOUD_ENV:n,...t.octane?{TSCLOUD_OCTANE:"1"}:{},...t.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...f?{TSCLOUD_CACHE_TABLE:`${i}-${n}-cache`}:{},...p?{TSCLOUD_QUEUE:u[0]}:{},...t.env??{}}),w=Boolean(t.efs),N=typeof t.efs==="object"?t.efs:{},k=N.mountPath??"/mnt/local",O=w&&!N.accessPointArn,le=N.accessPointArn??(O?d.getAtt("EfsAccessPoint","Arn"):void 0),j=t.vpc?.subnets??[],ne=j.length>0,U=t.cache?.driver==="elasticache"||t.database?.connection==="aurora-serverless"||Boolean(t.rdsProxy)||w;if(U&&!ne)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let Re=ne?{VpcConfig:{SubnetIds:j,SecurityGroupIds:[...t.vpc?.securityGroups??[],...U?[d.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},je=O?j.map((I,M)=>`EfsMountTarget${M}`):[],kt=w?{FileSystemConfigs:[{Arn:le,LocalMountPath:k}]}:{};if(w)R[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function ue(I,M,F,L,se,Mt,qe,Ee=T){A[`${I}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${M}`,RetentionInDays:m}};let ze=[...e.runtimeLayers??[],...t.lambdaInsights?[t.lambdaInsights.layerArn]:[]],Vn=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")},...ze.length?{Layers:[...new Set(ze)]}:{}};A[I]={Type:"AWS::Lambda::Function",DependsOn:[`${I}LogGroup`,...je],Properties:{FunctionName:M,Architectures:[a],MemorySize:se,Timeout:Mt,Role:d.getAtt("AppRole","Arn"),Environment:{Variables:D(L)},EphemeralStorage:{Size:Ee},...Vn,...qe!==void 0?{ReservedConcurrentExecutions:qe}:{},...Re,...kt}}}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),p)ue("QueueFunction",c.queue,r.queue,"queue",t.queueMemory??1024,t.queueTimeout??120,void 0,t.queueTmpStorage??T);let ie=(t.provisionedConcurrency??0)>0?t.provisionedConcurrency:0,de=["HttpFunction","CliFunction",...p?["QueueFunction"]:[]];if(ie)for(let I of de)A[`${I}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:d.ref(I)}},A[`${I}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:d.ref(I),Name:"live",FunctionVersion:d.getAtt(`${I}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:ie}}};let Pe=(I)=>ie?d.ref(`${I}Alias`):d.getAtt(I,"Arn"),me=(I)=>ie?d.ref(`${I}Alias`):d.ref(I);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:Pe("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}/*/*")}},P.HttpApiEndpoint={Description:"HTTP API endpoint",Value:d.getAtt("HttpApi","ApiEndpoint")},P.HttpApiId={Description:"HTTP API id",Value:d.ref("HttpApi")};let be=(Array.isArray(t.domain)?t.domain:t.domain?[t.domain]:[]).filter(Boolean);if(be.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 I=t.certificateArn;if(!I)A.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:be[0],...be.length>1?{SubjectAlternativeNames:be.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:be.map((M)=>({DomainName:M,HostedZoneId:t.hostedZoneId}))}},I=d.ref("HttpCertificate");be.forEach((M,F)=>{let L=`HttpDomain${F}`;if(A[L]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:M,DomainNameConfigurations:[{CertificateArn:I,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")}}};P[`CustomDomain${F}`]={Description:`Custom domain ${M}`,Value:M},P[`CustomDomainTarget${F}`]={Description:`Point ${M} (CNAME/alias) at this APIGW regional domain`,Value:d.getAtt(L,"RegionalDomainName")}})}if(p)A.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${i}-${n}-dlq`,MessageRetentionPeriod:1209600}},l.forEach((I,M)=>{let F=`AppQueue${M}`,L=t.queueTimeout??120;A[F]={Type:"AWS::SQS::Queue",Properties:{QueueName:I.name,VisibilityTimeout:Math.min(43200,L*6),RedrivePolicy:{deadLetterTargetArn:d.getAtt("AppQueueDlq","Arn"),maxReceiveCount:t.queueTries??3}}};let se=I.concurrency??t.queueConcurrency;A[`${F}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:d.getAtt(F,"Arn"),FunctionName:me("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...se?{ScalingConfig:{MaximumConcurrency:Math.max(2,se)}}:{}}},P[`QueueUrl${M}`]={Description:`Queue URL: ${I.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:Pe("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"||p);for(let L of F){let se=L.charAt(0).toUpperCase()+L.slice(1),Mt=Math.ceil(t.warm/5),qe=0;for(let Ee=0;Ee<Mt;Ee++){let ze=Math.min(5,t.warm-qe);A[`Warmer${se}Rule${Ee}`]={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${n}-warmer-${L}-${Ee}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:ze},(Vn,Cs)=>({Id:`warm-${L}-${Ee}-${Cs}`,Arn:d.getAtt(M[L],"Arn"),Input:JSON.stringify({warmer:!0})}))}},qe+=ze}A[`Warmer${se}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(f)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}}},P.CacheTableName={Description:"DynamoDB cache table",Value:d.ref("CacheTable")};if(S){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"}}};P.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}")}}}]}}},P.AssetsBucketName={Description:"Assets bucket",Value:d.ref("AssetsBucket")},P.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:d.getAtt("AssetsDistribution","DomainName")}}if(t.firewall?.enabled){let I=[],M=0;if(t.firewall.rateLimit)I.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 se=F[L];if(!se)continue;I.push({Name:`managed-${L}`,Priority:M++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:se}},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:I,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${n}-waf`}}},P.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(ne&&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`}]}},j.forEach((I,M)=>{A[`EfsMountTarget${M}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:d.ref("EfsFileSystem"),SubnetId:I,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"}}}},P.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:j}},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}},P.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:j}},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")}},P.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:j,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")]}},P.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:d.getAtt("DbProxy","Endpoint")};if(P.HttpFunctionName={Description:"HTTP function name",Value:d.ref("HttpFunction")},P.CliFunctionName={Description:"CLI function name",Value:d.ref("CliFunction")},p)P.QueueFunctionName={Description:"Queue function name",Value:d.ref("QueueFunction")};let Me={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:P},Ke={};for(let I of Object.values(A))Ke[I.Type]=(Ke[I.Type]??0)+1;return{template:Me,functionNames:c,queueNames:u,resourceSummary:Ke}}var zc=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function Qc(e){let t=`php${e.replace(".","")}`;return zc.map((n)=>`${t}-php-${n}`)}function On(e,t){let n=`php${e.replace(".","")}`,r=Qc(e).join(" \\\n "),i=`/opt/remi/${n}/root`,s=`/etc/opt/remi/${n}`;return`${t?`FROM almalinux:9 AS ${t}`:"FROM almalinux:9"}
|
|
7286
|
+
${p}`)}let c=o.outputs[0],l=Buffer.from(await c.arrayBuffer()),u="index",m=fe([{name:`${u}.mjs`,data:l}]);return{zip:m,bundle:l,sha256:al(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{Jc(s,{recursive:!0,force:!0})}}var ol=["18","20","22"];function cl(e){if(!e)return"22";let t=String(e).match(/(\d+)/);return t?t[1]:"22"}function Zi(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=cl(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&ol.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 Xi(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 kA(e,t,n){return Xi(e,t,n).map((r)=>r.name)}function MA(e){let{app:t,environment:n,handlers:r}=e,i=e.config.project.slug,s=Zi(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=Xi(t,i,n),u=l.map((I)=>I.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",f=(t.cache?.driver??"dynamodb")==="dynamodb",b=Boolean(t.assets),v=Xn(i,n),T=t.tmpStorage??512,A={},P={},R=[{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)R[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(f)R[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:R}};let D=(I)=>({TSCLOUD_LAMBDA_MODE:I,TSCLOUD_ENV:n,...t.octane?{TSCLOUD_OCTANE:"1"}:{},...t.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...f?{TSCLOUD_CACHE_TABLE:`${i}-${n}-cache`}:{},...m?{TSCLOUD_QUEUE:u[0]}:{},...t.env??{}}),w=Boolean(t.efs),N=typeof t.efs==="object"?t.efs:{},k=N.mountPath??"/mnt/local",O=w&&!N.accessPointArn,le=N.accessPointArn??(O?d.getAtt("EfsAccessPoint","Arn"):void 0),j=t.vpc?.subnets??[],ne=j.length>0,U=t.cache?.driver==="elasticache"||t.database?.connection==="aurora-serverless"||Boolean(t.rdsProxy)||w;if(U&&!ne)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let Pe=ne?{VpcConfig:{SubnetIds:j,SecurityGroupIds:[...t.vpc?.securityGroups??[],...U?[d.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},qe=O?j.map((I,M)=>`EfsMountTarget${M}`):[],Bt=w?{FileSystemConfigs:[{Arn:le,LocalMountPath:k}]}:{};if(w)R[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function ue(I,M,F,L,se,Ft,Qe,we=T){A[`${I}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[I]={Type:"AWS::Lambda::Function",DependsOn:[`${I}LogGroup`,...qe],Properties:{FunctionName:M,Architectures:[a],MemorySize:se,Timeout:Ft,Role:d.getAtt("AppRole","Arn"),Environment:{Variables:D(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 ie=(t.provisionedConcurrency??0)>0?t.provisionedConcurrency:0,de=["HttpFunction","CliFunction",...m?["QueueFunction"]:[]];if(ie)for(let I of de)A[`${I}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:d.ref(I)}},A[`${I}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:d.ref(I),Name:"live",FunctionVersion:d.getAtt(`${I}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:ie}}};let Ee=(I)=>ie?d.ref(`${I}Alias`):d.getAtt(I,"Arn"),me=(I)=>ie?d.ref(`${I}Alias`):d.ref(I);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}/*/*")}},P.HttpApiEndpoint={Description:"HTTP API endpoint",Value:d.getAtt("HttpApi","ApiEndpoint")},P.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 I=t.certificateArn;if(!I)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}))}},I=d.ref("HttpCertificate");Se.forEach((M,F)=>{let L=`HttpDomain${F}`;if(A[L]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:M,DomainNameConfigurations:[{CertificateArn:I,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")}}};P[`CustomDomain${F}`]={Description:`Custom domain ${M}`,Value:M},P[`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((I,M)=>{let F=`AppQueue${M}`,L=t.queueTimeout??120;A[F]={Type:"AWS::SQS::Queue",Properties:{QueueName:I.name,VisibilityTimeout:Math.min(43200,L*6),RedrivePolicy:{deadLetterTargetArn:d.getAtt("AppQueueDlq","Arn"),maxReceiveCount:t.queueTries??3}}};let se=I.concurrency??t.queueConcurrency;A[`${F}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:d.getAtt(F,"Arn"),FunctionName:me("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...se?{ScalingConfig:{MaximumConcurrency:Math.max(2,se)}}:{}}},P[`QueueUrl${M}`]={Description:`Queue URL: ${I.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 se=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${se}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,xs)=>({Id:`warm-${L}-${we}-${xs}`,Arn:d.getAtt(M[L],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Qe+=Je}A[`Warmer${se}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(f)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}}},P.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"}}};P.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}")}}}]}}},P.AssetsBucketName={Description:"Assets bucket",Value:d.ref("AssetsBucket")},P.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:d.getAtt("AssetsDistribution","DomainName")}}if(t.firewall?.enabled){let I=[],M=0;if(t.firewall.rateLimit)I.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 se=F[L];if(!se)continue;I.push({Name:`managed-${L}`,Priority:M++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:se}},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:I,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${n}-waf`}}},P.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(ne&&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`}]}},j.forEach((I,M)=>{A[`EfsMountTarget${M}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:d.ref("EfsFileSystem"),SubnetId:I,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"}}}},P.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:j}},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}},P.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:j}},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")}},P.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:j,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")]}},P.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:d.getAtt("DbProxy","Endpoint")};if(P.HttpFunctionName={Description:"HTTP function name",Value:d.ref("HttpFunction")},P.CliFunctionName={Description:"CLI function name",Value:d.ref("CliFunction")},m)P.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:P},ze={};for(let I of Object.values(A))ze[I.Type]=(ze[I.Type]??0)+1;return{template:Le,functionNames:c,queueNames:u,resourceSummary:ze}}var ll=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function ul(e){let t=`php${e.replace(".","")}`;return ll.map((n)=>`${t}-php-${n}`)}function Wn(e,t){let n=`php${e.replace(".","")}`,r=ul(e).join(" \\\n "),i=`/opt/remi/${n}/root`,s=`/etc/opt/remi/${n}`;return`${t?`FROM almalinux:9 AS ${t}`:"FROM almalinux:9"}
|
|
7287
7287
|
|
|
7288
7288
|
# Build PHP on AlmaLinux 9 (where Remi's version-isolated SCL packages install
|
|
7289
7289
|
# cleanly — Remi's release RPM rejects Amazon Linux 2023). AlmaLinux 9 shares
|
|
@@ -7323,9 +7323,9 @@ RUN printf 'extension_dir=/opt/php/lib/php/modules\\n' > /opt/php/etc/php.ini &&
|
|
|
7323
7323
|
# Runtime assets (bootstrap, runtime loops, fpm config) are added by the build
|
|
7324
7324
|
# orchestrator after the image is produced. Export /opt as the layer payload.
|
|
7325
7325
|
CMD ["true"]
|
|
7326
|
-
`}function
|
|
7327
|
-
${
|
|
7328
|
-
${
|
|
7326
|
+
`}function es(e={}){let t=e.phpVersion??"8.3";return`# ts-cloud PHP ${t} runtime layer (generated) — AWS Lambda provided.al2023.
|
|
7327
|
+
${Wn(t)}`}function BA(e){if(e.kind==="php"){let n=e.phpVersion??"8.3";return`# ts-cloud serverless PHP app image (generated, multi-stage).
|
|
7328
|
+
${Wn(n,"phpbuild")}
|
|
7329
7329
|
|
|
7330
7330
|
FROM public.ecr.aws/lambda/provided:al2023
|
|
7331
7331
|
# Bake the relocated PHP runtime from the build stage.
|
|
@@ -7344,7 +7344,7 @@ COPY app/ \${LAMBDA_TASK_ROOT}/
|
|
|
7344
7344
|
|
|
7345
7345
|
# Per-function CMD (e.g. index.http) is supplied via ImageConfig.Command.
|
|
7346
7346
|
CMD [ "index.http" ]
|
|
7347
|
-
`}import{execFileSync as wt}from"node:child_process";import{mkdtempSync as ji,readFileSync as It,rmSync as Ki}from"node:fs";import{tmpdir as qi}from"node:os";import{dirname as Jc,join as Te}from"node:path";import{fileURLToPath as Yc}from"node:url";function zi(){return Jc(Yc(import.meta.url))}function Qi(){return It(Te(zi(),"runtime.mjs"),"utf-8")}function Ji(e){return It(Te(zi(),`${e}-bootstrap`),"utf-8")}function CA(e){let t=e.architecture??"x86_64",n=t==="arm64"?"arm64":"x64",r=e.version.replace(/^v/,""),i=e.onStep??(()=>{}),s=ji(Te(qi(),"tscloud-node-layer-"));try{let a=r.includes(".")?r:Zc(r),o=`node-v${a}-linux-${n}`,c=`https://nodejs.org/dist/v${a}/${o}.tar.xz`;i(`downloading Node ${a} (${t})`);let l=Te(s,"node.tar.xz");Yi(c,l),i("extracting node binary"),wt("tar",["-xf",l,"-C",s,`${o}/bin/node`],{stdio:"inherit"});let u=It(Te(s,o,"bin","node"));i("packaging layer");let p=[{name:"bootstrap",data:Ji("node"),mode:493},{name:"runtime.mjs",data:Qi(),mode:420},{name:"bin/node",data:u,mode:493}];return{zip:he(p),architecture:t,version:a,fileCount:p.length}}finally{Ki(s,{recursive:!0,force:!0})}}function vA(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=ji(Te(qi(),"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=Te(s,"bun.zip");Yi(a,o),i("extracting bun binary"),wt("unzip",["-o","-q",o,"-d",s],{stdio:"inherit"});let c=It(Te(s,n,"bun"));i("packaging layer");let l=[{name:"bootstrap",data:Ji("bun"),mode:493},{name:"runtime.mjs",data:Qi(),mode:420},{name:"bin/bun",data:c,mode:493}];return{zip:he(l),architecture:t,version:r||"latest",fileCount:l.length}}finally{Ki(s,{recursive:!0,force:!0})}}function Yi(e,t){wt("curl",["-fsSL","-o",t,e],{stdio:["ignore","ignore","inherit"]})}function Zc(e){let t=wt("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 rl}from"node:async_hooks";import{createHash as Xc}from"node:crypto";var Zi="x-ts-cloud-invoke-depth",Xi="x-ts-cloud-invoke-chain",es="x-ts-cloud-trace-id";function el(e){return Xc("sha256").update(e).digest("hex").slice(0,8)}var Dt={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function $n(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 tl(e,t=64){if(!e)return[];return e.split(".").map((n)=>n.trim()).filter((n)=>/^[0-9a-f]{8}$/.test(n)).slice(-t)}function nl(e,t=Dt){let n=el(e.functionId),r=tl($n(e.headers,Xi)),i=e.traceId??$n(e.headers,es)??crypto.randomUUID(),s=[...r,n],a=r.filter((p)=>p===n).length,o=r[r.length-1]===n,c=Number.parseInt($n(e.headers,Zi)??"",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:{[Zi]:String(l),[Xi]:s.join("."),[es]:i}}}var ts={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 Bn{limits;clock;traces=new Map;breakers=new Map;constructor(e=Dt,t=()=>Date.now()){this.limits=e;this.clock=t}check(e){let t=this.clock();this.expireTraces(t);let n=nl(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:ts[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 ns(e){return{...e.propagate}}function rs(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??ts[e.reason],depth:e.depth,traceId:e.traceId}}}var ss=new rl;function is(e){let t=globalThis.process?.env?.[e];if(t==null||t==="")return;return t!=="0"&&t.toLowerCase()!=="false"}function il(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function sl(e){let t=e===!1?{enabled:!1}:e??{},n=is("TS_CLOUD_RECURSION_PROTECTION"),r=is("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:n??t.enabled??!0,detectionOnly:r??t.detectionOnly??!1,limits:{...Dt,...t.limits},functionId:t.functionId??il()}}var ke,fe;function al(){let e=globalThis.fetch;if(!e||ke===e)return()=>{};fe=e;let t=async(n,r)=>{let i=ss.getStore();if(!i)return fe(n,r);let s=new Headers(r?.headers??(n instanceof Request?n.headers:void 0));for(let[a,o]of Object.entries(ns(i)))s.set(a,o);if(n instanceof Request)return fe(new Request(n,{headers:s}),r);return fe(n,{...r,headers:s})};return Object.assign(t,e),globalThis.fetch=t,ke=t,()=>{if(globalThis.fetch===ke&&fe)globalThis.fetch=fe;ke=void 0}}var Nt,Fn;function ol(e){if(!Nt||JSON.stringify(Fn)!==JSON.stringify(e))Nt=new Bn(e),Fn=e;return Nt}function IA(){if(Nt=void 0,Fn=void 0,ke&&fe&&globalThis.fetch===ke)globalThis.fetch=fe;ke=void 0,fe=void 0}function as(e,t){let n=sl(t);if(!n.enabled)return;let r=ol(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 os(e,t){return al(),ss.run(e,t)}function kA(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 cl=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function ll(e){if(!e)return!0;return cl.test(e)}function ul(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 dl(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 cs(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=ll(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 ml(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=ul(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=as(n.headers??{},t?.recursionProtection);if(i?.blocked){let a=rs(i.verdict);return{statusCode:a.status,headers:{...a.headers,"retry-after":"60"},body:JSON.stringify(a.body),isBase64Encoded:!1}}let s=dl(n);if(!i){let a=await e(s);return cs(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 os(i.verdict,async()=>cs(await e(s)))}}function pl(e){try{return JSON.parse(e)}catch{return e}}function gl(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(pl(r.body),r)}catch{n.push({itemIdentifier:r.messageId})}return{batchItemFailures:n}}}function yl(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 MA(e,t){return{http:ml(e.fetch,t),queue:gl(e.queue),cli:yl(e.cli)}}function ls(e={}){let t=e.socketPath??"/tmp/.tscloud-fpm.sock",n=e.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
|
|
7347
|
+
`}import{execFileSync as kt}from"node:child_process";import{mkdtempSync as ts,readFileSync as Mt,rmSync as ns}from"node:fs";import{tmpdir as rs}from"node:os";import{dirname as dl,join as Re}from"node:path";import{fileURLToPath as ml}from"node:url";function is(){return dl(ml(import.meta.url))}function ss(){return Mt(Re(is(),"runtime.mjs"),"utf-8")}function as(e){return Mt(Re(is(),`${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=ts(Re(rs(),"tscloud-node-layer-"));try{let a=r.includes(".")?r:pl(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");os(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:as("node"),mode:493},{name:"runtime.mjs",data:ss(),mode:420},{name:"bin/node",data:u,mode:493}];return{zip:fe(m),architecture:t,version:a,fileCount:m.length}}finally{ns(s,{recursive:!0,force:!0})}}function KA(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=ts(Re(rs(),"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");os(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:as("bun"),mode:493},{name:"runtime.mjs",data:ss(),mode:420},{name:"bin/bun",data:c,mode:493}];return{zip:fe(l),architecture:t,version:r||"latest",fileCount:l.length}}finally{ns(s,{recursive:!0,force:!0})}}function os(e,t){kt("curl",["-fsSL","-o",t,e],{stdio:["ignore","ignore","inherit"]})}function pl(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 bl}from"node:async_hooks";import{createHash as gl}from"node:crypto";var cs="x-ts-cloud-invoke-depth",ls="x-ts-cloud-invoke-chain",us="x-ts-cloud-trace-id";function yl(e){return gl("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 hl(e,t=64){if(!e)return[];return e.split(".").map((n)=>n.trim()).filter((n)=>/^[0-9a-f]{8}$/.test(n)).slice(-t)}function fl(e,t=Lt){let n=yl(e.functionId),r=hl(Vn(e.headers,ls)),i=e.traceId??Vn(e.headers,us)??crypto.randomUUID(),s=[...r,n],a=r.filter((m)=>m===n).length,o=r[r.length-1]===n,c=Number.parseInt(Vn(e.headers,cs)??"",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:{[cs]:String(l),[ls]:s.join("."),[us]:i}}}var ds={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=fl(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:ds[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 ms(e){return{...e.propagate}}function ps(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??ds[e.reason],depth:e.depth,traceId:e.traceId}}}var ys=new bl;function gs(e){let t=globalThis.process?.env?.[e];if(t==null||t==="")return;return t!=="0"&&t.toLowerCase()!=="false"}function Sl(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function Al(e){let t=e===!1?{enabled:!1}:e??{},n=gs("TS_CLOUD_RECURSION_PROTECTION"),r=gs("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:n??t.enabled??!0,detectionOnly:r??t.detectionOnly??!1,limits:{...Lt,...t.limits},functionId:t.functionId??Sl()}}var Me,be;function Cl(){let e=globalThis.fetch;if(!e||Me===e)return()=>{};be=e;let t=async(n,r)=>{let i=ys.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(ms(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 vl(e){if(!Ot||JSON.stringify(Hn)!==JSON.stringify(e))Ot=new Un(e),Hn=e;return Ot}function ZA(){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=Al(t);if(!n.enabled)return;let r=vl(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 fs(e,t){return Cl(),ys.run(e,t)}function nC(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 Tl=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function Rl(e){if(!e)return!0;return Tl.test(e)}function Pl(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 El(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 bs(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=Rl(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 wl(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=Pl(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=ps(i.verdict);return{statusCode:a.status,headers:{...a.headers,"retry-after":"60"},body:JSON.stringify(a.body),isBase64Encoded:!1}}let s=El(n);if(!i){let a=await e(s);return bs(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 fs(i.verdict,async()=>bs(await e(s)))}}function Il(e){try{return JSON.parse(e)}catch{return e}}function Dl(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(Il(r.body),r)}catch{n.push({itemIdentifier:r.messageId})}return{batchItemFailures:n}}}function Nl(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 rC(e,t){return{http:wl(e.fetch,t),queue:Dl(e.queue),cli:Nl(e.cli)}}function Ss(e={}){let t=e.socketPath??"/tmp/.tscloud-fpm.sock",n=e.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
|
|
7348
7348
|
[global]
|
|
7349
7349
|
daemonize = no
|
|
7350
7350
|
error_log = ${e.errorLog??"/tmp/storage/logs/php-fpm.log"}
|
|
@@ -7361,4 +7361,4 @@ decorate_workers_output = no
|
|
|
7361
7361
|
php_admin_value[error_log] = /dev/stderr
|
|
7362
7362
|
php_admin_flag[log_errors] = on
|
|
7363
7363
|
clear_env = no
|
|
7364
|
-
`}import{readFileSync as hl}from"node:fs";import{dirname as fl,join as us}from"node:path";import{fileURLToPath as bl}from"node:url";function Sl(){return us(fl(bl(import.meta.url)),"runtime-assets")}function Gn(){let e=Sl(),t=(n)=>hl(us(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:ls(),mode:420}]}function YA(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 ds=["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 xt}from"node:child_process";import{existsSync as Al,mkdirSync as Cl,mkdtempSync as vl,readdirSync as Tl,readFileSync as Rl,rmSync as Pl,statSync as ms,writeFileSync as El}from"node:fs";import{tmpdir as wl}from"node:os";import{join as He,relative as Il}from"node:path";function*ps(e){for(let t of Tl(e)){let n=He(e,t);if(ms(n).isDirectory())yield*ps(n);else yield n}}function aC(e={}){let t=e.architecture??"x86_64",n=e.platform??(t==="arm64"?"linux/arm64":"linux/amd64"),r=e.onStep??(()=>{}),i=vl(He(wl(),"tscloud-php-layer-")),s="tscloud-php-layer:build";try{El(He(i,"Dockerfile"),Hi(e)),r("Building PHP runtime image (docker)"),xt("docker",["build","--platform",n,"-t","tscloud-php-layer:build",i],{stdio:"inherit"}),r("Extracting /opt/php from image");let a=xt("docker",["create","--platform",n,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),o=He(i,"opt");Cl(o,{recursive:!0});try{xt("docker",["cp",`${a}:/opt/php`,He(o,"php")],{stdio:"inherit"})}finally{xt("docker",["rm",a],{stdio:"ignore"})}if(!Al(He(o,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let c=[];for(let m of ps(o)){let g=Il(o,m).replace(/\\/g,"/"),y=ms(m).mode&73?493:420;c.push({name:g,data:Rl(m),mode:y})}r("Injecting runtime assets");let l=new Set(Gn().map((m)=>m.path)),u=c.filter((m)=>!l.has(m.name));for(let m of Gn())u.push({name:m.path,data:m.contents,mode:m.mode});return r("Packaging layer ZIP"),{zip:he(u),architecture:t,fileCount:u.length}}finally{Pl(i,{recursive:!0,force:!0})}}import{execSync as Dl}from"node:child_process";import{createHash as Nl}from"node:crypto";import{readdirSync as xl,readFileSync as kl,statSync as gs}from"node:fs";import{join as Ml,relative as ys,resolve as _n}from"node:path";var Ll=[".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 Ol(e,t){return t.some((n)=>e===n||e.startsWith(`${n}/`))}function*hs(e,t,n){for(let r of xl(e)){let i=Ml(e,r),s=ys(t,i).replace(/\\/g,"/");if(Ol(s,n))continue;if(gs(i).isDirectory())yield*hs(i,t,n);else yield i}}function $l(e){if(e.skipBuild)return;let t=_n(e.projectRoot??process.cwd()),n=e.app.build??ds;for(let r of n)e.onStep?.(`build: ${r}`),Dl(r,{stdio:"inherit",cwd:t})}function Bl(e,t=[]){let n=_n(e),r=[...Ll,Oe(),...t],i=[];for(let s of hs(n,n,r)){let a=ys(n,s).replace(/\\/g,"/"),o=(gs(s).mode&73)!==0;i.push({name:a,data:kl(s),mode:o?493:420})}return i}function yC(e){let t=_n(e.projectRoot??process.cwd());$l(e),e.onStep?.("packaging application tree");let n=Bl(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:Nl("sha256").update(r).digest("hex"),handlers:{http:i,queue:e.app.handlers?.queue??i,cli:e.app.handlers?.cli??i},fileCount:n.length}}class fs{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 TC=new fs;class Wn{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 Fl=new Wn;class bs{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 EC=new bs;class Ss{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 IC=new Ss;class As{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 NC=new As;export{yn as ABTestManager,mt as AI,To as AWSAPIError,dn as AWSConfigManager,Wm as AWS_PSEUDO_PARAMETERS,ce as AWS_REGIONS,ca as ApiGateway,$e as Arn,H as AssetHasher,J as Auth,ln as BackupManager,Gi as BatchProcessingManager,gn as BlueGreenManager,Di as BounceComplaintHandler,Ai as BuildOptimizationManager,re as CDN,Xi as CHAIN_HEADER,Bt as CLOUDFRONT_FAILOVER_STATUS_CODES,Yh as COMMON_CROSS_ACCOUNT_ROLES,oa as Cache,lt as CanaryManager,fi as CertificateManager,ye as CloudError,vr as CloudFormationBuilder,lo as CloudFormationClient,Co as CloudFrontClient,mn as CloudTrailManager,nc as CommandHistory,Z as Communication,x as Compute,Tt as ConfigurationError,An as ContainerRegistryManager,Ce as CredentialError,si as CrossRegionReferenceManager,Va as DASHBOARD_ENTRY,ja as DASHBOARD_PORT_BASE,Ka as DASHBOARD_PORT_SPAN,Wa as DASHBOARD_STATE_DIR,Qn as DEFAULT_FAILOVER_STATUS_CODES,Dt as DEFAULT_RECURSION_LIMITS,X as DEFAULT_SERVICE_LIMITS,Ot as DEFAULT_STATE_DIR,Zi as DEPTH_HEADER,Fi as DLQMonitoringManager,z as DNS,wi as DNSSECManager,Vt as Database,yi as DatabaseUserManager,q as DebugLogger,zs as DependencyGraph,Y as Deployment,vo as DeploymentError,un as DisasterRecoveryManager,G as Email,Mi as EmailAdvanced,Ni as EmailAnalyticsManager,Li as EmailHandlers,ki as EmailTemplateManager,Ro as ErrorCodes,Bi as FIFOQueueManager,en as FileCache,Je as FileSystem,d as Fn,ai as GlobalResourceManager,pn as GuardDutyManager,Lo as HashCache,bs as HealthCheckManager,Si as ImageScanningManager,Ae as JobLoader,ds as LARAVEL_SERVERLESS_BUILD_STEPS,Ti as LambdaConcurrencyManager,Ei as LambdaDLQManager,Ri as LambdaDestinationsManager,Ci as LambdaLayersManager,Pi as LambdaVPCManager,vi as LambdaVersionsManager,fn as LogsManager,Kc as MANAGED_NODE_VERSIONS,Er as MANAGEMENT_DASHBOARD_SITE_PREFIX,ee as Messaging,mi as MetricsManager,pi as MigrationManager,Zr as MockCloudFormation,ei as MockDynamoDB,Xr as MockS3,sr as Monitoring,li as MultiAccountManager,ii as MultiRegionManager,zo as MultiStepProgress,B as Network,Ss as NetworkSecurityManager,Jn as ORIGIN_GROUP_ALLOWED_METHODS,Lu as ORIGIN_GROUP_ID_SUFFIX,ui as OrganizationManager,Ll as PHP_DEFAULT_EXCLUDES,zc as PHP_LAYER_EXTENSIONS,_ as ParameterStore,gi as PerformanceManager,oe as Permissions,ge as Phone,Oi as PhoneAdvanced,Xn as PhoneHandlers,an as PreviewEnvironmentManager,on as PreviewNotificationService,qo as ProgressBar,hn as ProgressiveDeploymentManager,qs as Pseudo,ae as Queue,_i as QueueManagementManager,Wl as QueuePresets,ac as RECOMMENDED_ACCOUNT_STRUCTURES,Jh as RECOMMENDED_SCPS,Xo as REPL,tc as REPLCommandBuilder,ec as REPLContext,Oo as RateLimiter,Vl as RealtimePresets,Bn as RecursionGuard,yt as Redirects,oi as RegionPairManager,pe as Registry,bn as ReplicaManager,As as ResourceManagementManager,Ii as Route53ResolverManager,vn as Route53RoutingManager,Yt as S3Client,K as S3Error,Q as SMS,Un as STATE_DIR_ENV_VAR,Xe as Search,Ze as Secrets,Sn as SecretsManager,hi as SecretsRotationManager,W as Security,De as SecurityHubManager,bi as SecurityScanningManager,xi as SenderReputationManager,Cn as ServiceMeshManager,aa as Sftp,$i as SmsAdvanced,ir as SmsHandlers,Qo as Spinner,ci as StackDependencyManager,md as StacksIntegration,fs as StaticSiteManager,we as Storage,Wn as StorageAdvancedManager,Ne as SyntheticsManager,es as TRACE_HEADER,Jo as TaskList,Ls as TemplateBuilder,tn as TemplateCache,Hr as ValidationError,la as Workflow,di as XRayManager,yc as abTestManager,Ru as analyzeStackDiff,tA as artifactKey,Yn as assertOriginGroupMethods,lh as autocomplete,lc as awsConfigManager,oc as backupManager,by as batch,OS as batchProcessingManager,pc as blueGreenManager,$b as bounceComplaintHandler,vA as buildBunRuntimeLayerZip,Ep as buildCloudFormationTemplate,nu as buildMailEnv,CA as buildNodeRuntimeLayerZip,yb as buildOptimizationManager,Ft as buildOriginGroup,Ou as buildOriginGroups,aC as buildPhpRuntimeLayerZip,gc as canaryManager,Iy as categorizeChanges,lb as certificateManager,Qg as checkIAMPermissions,as as checkInvocation,Xg as checkServiceQuotas,$o as chunk,Rg as clearSigningKeyCache,Go as cloudConfigSchema,uc as cloudTrailManager,Bl as collectPhpAppEntries,dg as composePresets,lA as composeServerlessAppTemplate,Cc as containerRegistryManager,_p as createApiBackendPreset,yl as createCliHandler,kg as createCredentialProvider,ag as createDashboardSite,Jp as createDataPipelinePreset,Ur as createError,Bp as createExistingStaticFullStackPreset,Fp as createFullStackAppPreset,MA as createHandlers,ml as createHttpHandler,Hp as createJamstackPreset,ng as createLaravelPreset,Zp as createMLApiPreset,Kp as createMicroservicesPreset,Wy as createMockAWS,Np as createNodeJsServerPreset,kp as createNodeJsServerlessPreset,mg as createPreset,xr as createPresignedUrl,Ag as createPresignedUrlAsync,gl as createQueueHandler,zp as createRealtimeAppPreset,Ao as createS3Client,ig as createServerlessLaravelPreset,Lp as createServerlessNodePreset,Ip as createStaticSitePreset,eg as createTraditionalWebAppPreset,Vp as createWordPressPreset,he as createZip,wh as crossRegionReferenceManager,ib as databaseUserManager,Yr as defaultLocalConfig,Jl as deploymentCoexistenceError,qa as deriveManagementDashboardPort,jn as detectDeploymentTargets,Hg as detectMisconfigurations,Dr as detectServiceRegion,Py as diffTemplates,MS as dlqMonitoringManager,kb as dnssecManager,cc as drManager,Fb as emailAnalyticsManager,Vb as emailTemplateManager,dl as eventToRequest,wr as extendPreset,xS as fifoQueueManager,hy as findChangedFiles,tf as formatAccountStructure,Xy as formatBytes,Pu as formatDiff,eh as formatDuration,dh as formatFlagSuggestions,hh as formatHistory,fh as formatHistoryStats,nh as formatKeyValue,th as formatList,Zy as formatProgressBar,sc as formatRegion,_h as formatRegionList,sh as formatSuggestion,Jy as formatTable,Yy as formatTree,so as fromEC2Metadata,ao as fromECSMetadata,no as fromEnvironment,ro as fromSharedCredentials,oo as fromWebIdentity,el as functionFingerprint,pA as generateAppImageDockerfile,vf as generateApprovalConfig,Wi as generateBootstrap,Vo as generateCleanupWorkflow,Uo as generateCostReportWorkflow,Xh as generateCrossAccountRoleCF,Sf as generateDeploymentConfig,pf as generateDeploymentPipeline,of as generateDeploymentWorkflow,h as generateLogicalId,ff as generateManualPipeline,df as generateMatrixWorkflow,Af as generateMultiEnvConfig,gf as generateMultiEnvPipeline,cf as generateMultiEnvWorkflow,lf as generatePRPreviewWorkflow,Tf as generateParallelConfig,ls as generatePhpFpmConfig,Hi as generatePhpLayerDockerfile,yf as generatePreviewPipeline,Wo as generatePreviewWorkflow,b as generateResourceName,Cf as generateScheduledConfig,hf as generateScheduledPipeline,uf as generateScheduledWorkflow,Wr as getAccountId,kh as getAllRegions,Bh as getClosestRegion,mh as getCommandUsage,oh as getContextualHelp,st as getCredentials,Dy as getDeploymentStrategy,Ny as getDiffStats,Ey as getDiffSummary,Po as getErrorDetails,sn as getLocalConfig,Fy as getLocalCredentials,By as getLocalEndpoint,Gy as getLocalEnvVars,ey as getQuotaUsageSummary,Zh as getRecommendedStructure,ot as getRegion,Wh as getRegionStats,Lh as getRegionsByCompliance,Mh as getRegionsByLocation,Oh as getRegionsByPricingTier,Eo as getRequiredPermissions,Pg as getSigningKeyCacheSize,du as getTimestamp,Ih as globalResourceManager,dc as guardDutyManager,Ja as hasManagementDashboardSite,my as hashBuffer,py as hashDirectory,zr as hashFile,gy as hashManifest,Qr as hashString,EC as healthCheckManager,pb as imageScanningManager,nl as inspectInvocation,al as installRecursionFetch,ss as invocationContext,ah as isLikelyTypo,$y as isLocalDevelopment,Ya as isManagementDashboardSiteName,Eg as isNodeCryptoAvailable,Zn as isS3RestEndpoint,Kl as isStateDirConfigured,ql as isStatePath,$h as isValidRegion,wg as isWebCryptoAvailable,Tb as lambdaConcurrencyManager,Db as lambdaDLQManager,Pb as lambdaDestinationsManager,Sb as lambdaLayersManager,wb as lambdaVPCManager,Cb as lambdaVersionsManager,YA as laravelServerlessEnvDefaults,fc as logsManager,xs as mailEnabled,tu as mailFirewallPorts,Ie as makeAWSRequest,vg as makeAWSRequestAsync,Cg as makeAWSRequestOnce,Tr as managementDashboardSiteName,Be as mergeInfrastructure,Qf as metricsManager,Xf as migrationManager,qh as multiAccountManager,Ph as multiRegionManager,IC as networkSecurityManager,zh as organizationManager,yC as packagePhpApp,nA as packageServerlessApp,rn as parallel,Sy as parallelMap,Ay as parallelWithRetry,tl as parseChain,Tg as parseJSONResponse,vt as parseXMLResponse,nb as performanceManager,On as phpLayerBuildStage,Qc as phpLayerPackages,Gn as phpRuntimeLayerAssets,_o as previewManager,Ho as previewNotifications,Ty as processInChunks,hc as progressiveDeploymentManager,ns as propagationHeaders,BS as queueManagementManager,yy as quickHash,rs as recursionBlockedResponse,Dh as regionPairManager,Sc as replicaManager,wy as requiresReplacement,IA as resetRecursionRuntime,kA as resolveApp,Zl as resolveAppDatabase,iu as resolveCloudProvider,We as resolveCredentials,za as resolveDashboardDomain,Qa as resolveDashboardDomains,Su as resolveDeployBucketName,Ql as resolveDeploymentMode,Zs as resolveFailoverStatusCodes,eu as resolveMailService,lg as resolveManagementDashboardSite,Za as resolveManagementDashboardSites,gu as resolveProjectStackName,cA as resolveQueueNames,Ui as resolveQueues,sl as resolveRecursionConfig,co as resolveRegion,Au as resolveServerlessAppStackName,Cu as resolveServerlessArtifactBucketName,qn as resolveServerlessAssetBucketName,Vi as resolveServerlessRuntime,fu as resolveSiteBucketName,hu as resolveSiteResourceName,yu as resolveSiteStackName,Ds as resolveStatePath,bu as resolveStorageBucketName,NC as resourceManagementManager,cs as responseToResult,Lb as route53ResolverManager,Tc as route53RoutingManager,Hc as runBuildHooks,$l as runPhpBuildHooks,mu as sanitizeName,ch as searchCommands,Ac as secretsManager,ab as secretsRotationManager,mc as securityHubManager,db as securityScanningManager,_b as senderReputationManager,Cy as sequence,vc as serviceMeshManager,jl as setStateDir,jc as sha256,ol as sharedRecursionGuard,Qi as sharedRuntimeLoop,V as signRequest,Nr as signRequestAsync,Nh as stackDependencyManager,Oe as stateDir,Hn as statePath,TC as staticSiteManager,Fl as storageAdvancedManager,ri as suggestCommand,uh as suggestFlags,Jg as suggestIAMPolicy,ty as suggestQuotaIncrease,Gh as suggestRegionPairs,Fh as suggestRegions,bc as syntheticsManager,Do as templateCache,ef as validateAccountStructure,Ly as validateAgainstSchema,ph as validateCommand,Ug as validateConfiguration,zg as validateCredentials,Ks as validateResourceLimits,Os as validateTemplate,js as validateTemplateSize,fg as withCDN,hg as withCache,yg as withDatabase,os as withInvocation,pg as withMonitoring,bg as withQueue,gg as withSecurity,vy as withTimeout,qf as xrayManager};
|
|
7364
|
+
`}import{readFileSync as xl}from"node:fs";import{dirname as kl,join as As}from"node:path";import{fileURLToPath as Ml}from"node:url";function Ll(){return As(kl(Ml(import.meta.url)),"runtime-assets")}function jn(){let e=Ll(),t=(n)=>xl(As(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:Ss(),mode:420}]}function CC(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 Cs=["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 Ol,mkdirSync as $l,mkdtempSync as Bl,readdirSync as Fl,readFileSync as Gl,rmSync as _l,statSync as vs,writeFileSync as Wl}from"node:fs";import{tmpdir as Vl}from"node:os";import{join as Ke,relative as Ul}from"node:path";function*Ts(e){for(let t of Fl(e)){let n=Ke(e,t);if(vs(n).isDirectory())yield*Ts(n);else yield n}}function NC(e={}){let t=e.architecture??"x86_64",n=e.platform??(t==="arm64"?"linux/arm64":"linux/amd64"),r=e.onStep??(()=>{}),i=Bl(Ke(Vl(),"tscloud-php-layer-")),s="tscloud-php-layer:build";try{Wl(Ke(i,"Dockerfile"),es(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(!Ol(Ke(o,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let c=[];for(let p of Ts(o)){let g=Ul(o,p).replace(/\\/g,"/"),y=vs(p).mode&73?493:420;c.push({name:g,data:Gl(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:fe(u),architecture:t,fileCount:u.length}}finally{_l(i,{recursive:!0,force:!0})}}import{execSync as Hl}from"node:child_process";import{createHash as jl}from"node:crypto";import{readdirSync as Kl,readFileSync as ql,statSync as Rs}from"node:fs";import{join as zl,relative as Ps,resolve as Kn}from"node:path";var Ql=[".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 Jl(e,t){return t.some((n)=>e===n||e.startsWith(`${n}/`))}function*Es(e,t,n){for(let r of Kl(e)){let i=zl(e,r),s=Ps(t,i).replace(/\\/g,"/");if(Jl(s,n))continue;if(Rs(i).isDirectory())yield*Es(i,t,n);else yield i}}function Yl(e){if(e.skipBuild)return;let t=Kn(e.projectRoot??process.cwd()),n=e.app.build??Cs;for(let r of n)e.onStep?.(`build: ${r}`),Hl(r,{stdio:"inherit",cwd:t})}function Zl(e,t=[]){let n=Kn(e),r=[...Ql,$e(),...t],i=[];for(let s of Es(n,n,r)){let a=Ps(n,s).replace(/\\/g,"/"),o=(Rs(s).mode&73)!==0;i.push({name:a,data:ql(s),mode:o?493:420})}return i}function GC(e){let t=Kn(e.projectRoot??process.cwd());Yl(e),e.onStep?.("packaging application tree");let n=Zl(t,e.exclude);if(!n.length)throw Error(`No files to package under ${t}`);let r=fe(n),i=e.app.handlers?.http??"public/index.php";return{zip:r,sha256:jl("sha256").update(r).digest("hex"),handlers:{http:i,queue:e.app.handlers?.queue??i,cli:e.app.handlers?.cli??i},fileCount:n.length}}class ws{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 qC=new ws;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 Xl=new qn;class Is{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 JC=new Is;class Ds{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 ZC=new Ds;class Ns{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 ev=new Ns;export{Cn as ABTestManager,ft as AI,Fo as AWSAPIError,fn as AWSConfigManager,dp as AWS_PSEUDO_PARAMETERS,ce as AWS_REGIONS,Ta as ApiGateway,Fe as Arn,H as AssetHasher,J as Auth,yn as BackupManager,Qi as BatchProcessingManager,An as BlueGreenManager,Gi as BounceComplaintHandler,Ni as BuildOptimizationManager,re as CDN,ls as CHAIN_HEADER,Vt as CLOUDFRONT_FAILOVER_STATUS_CODES,vf as COMMON_CROSS_ACCOUNT_ROLES,va as Cache,mt as CanaryManager,wi as CertificateManager,he as CloudError,kr as CloudFormationBuilder,Po as CloudFormationClient,$o as CloudFrontClient,bn as CloudTrailManager,fc as CommandHistory,Z as Communication,x as Compute,It as ConfigurationError,En as ContainerRegistryManager,ve as CredentialError,yi as CrossRegionReferenceManager,ro as DASHBOARD_ENTRY,ao as DASHBOARD_PORT_BASE,oo as DASHBOARD_PORT_SPAN,no as DASHBOARD_STATE_DIR,tr as DEFAULT_FAILOVER_STATUS_CODES,Lt as DEFAULT_RECURSION_LIMITS,X as DEFAULT_SERVICE_LIMITS,_t as DEFAULT_STATE_DIR,la as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,cs as DEPTH_HEADER,zi as DLQMonitoringManager,z as DNS,Bi as DNSSECManager,zt as Database,Pi as DatabaseUserManager,q as DebugLogger,ia as DependencyGraph,Y as Deployment,Bo as DeploymentError,hn as DisasterRecoveryManager,G as Email,Ui as EmailAdvanced,_i as EmailAnalyticsManager,Hi as EmailHandlers,Vi as EmailTemplateManager,Go as ErrorCodes,da as FAILOVER_REPLICA_POLICY_SID,qi as FIFOQueueManager,on as FileCache,Xe as FileSystem,d as Fn,hi as GlobalResourceManager,Sn as GuardDutyManager,Qo as HashCache,Is as HealthCheckManager,Di as ImageScanningManager,Ce as JobLoader,Cs as LARAVEL_SERVERLESS_BUILD_STEPS,Mi as LambdaConcurrencyManager,$i as LambdaDLQManager,Li as LambdaDestinationsManager,xi as LambdaLayersManager,Oi as LambdaVPCManager,ki as LambdaVersionsManager,Tn as LogsManager,ol as MANAGED_NODE_VERSIONS,$r as MANAGEMENT_DASHBOARD_SITE_PREFIX,ee as Messaging,vi as MetricsManager,Ti as MigrationManager,ci as MockCloudFormation,ui as MockDynamoDB,li as MockS3,yr as Monitoring,Si as MultiAccountManager,gi as MultiRegionManager,lc as MultiStepProgress,B as Network,Ds as NetworkSecurityManager,ir as ORIGIN_CONNECTION_ATTEMPTS,sr as ORIGIN_CONNECTION_TIMEOUT,nr as ORIGIN_GROUP_ALLOWED_METHODS,Qu as ORIGIN_GROUP_ID_SUFFIX,rr as ORIGIN_GROUP_SELECTION_CRITERIA,Ai as OrganizationManager,Ql as PHP_DEFAULT_EXCLUDES,ll as PHP_LAYER_EXTENSIONS,_ as ParameterStore,Ri as PerformanceManager,oe as Permissions,ye as Phone,ji as PhoneAdvanced,lr as PhoneHandlers,mn as PreviewEnvironmentManager,pn as PreviewNotificationService,cc as ProgressBar,vn as ProgressiveDeploymentManager,ra as Pseudo,ae as Queue,Ji as QueueManagementManager,nu as QueuePresets,Cc as RECOMMENDED_ACCOUNT_STRUCTURES,Cf as RECOMMENDED_SCPS,gc as REPL,hc as REPLCommandBuilder,yc as REPLContext,Jo as RateLimiter,ru as RealtimePresets,Un as RecursionGuard,At as Redirects,fi as RegionPairManager,pe as Registry,Rn as ReplicaManager,Ns as ResourceManagementManager,Fi as Route53ResolverManager,In as Route53RoutingManager,rn as S3Client,K as S3Error,Q as SMS,Qn as STATE_DIR_ENV_VAR,ua as STORAGE_FAILOVER_METADATA_KEY,nt as Search,tt as Secrets,Pn as SecretsManager,Ei as SecretsRotationManager,W as Security,Ne as SecurityHubManager,Ii as SecurityScanningManager,Wi as SenderReputationManager,wn as ServiceMeshManager,Ca as Sftp,Ki as SmsAdvanced,gr as SmsHandlers,uc as Spinner,bi as StackDependencyManager,Od as StacksIntegration,ws as StaticSiteManager,Ie as Storage,qn as StorageAdvancedManager,xe as SyntheticsManager,us as TRACE_HEADER,dc as TaskList,Hs as TemplateBuilder,cn as TemplateCache,ei as ValidationError,Ra as Workflow,Ci as XRayManager,Nc as abTestManager,Gu as analyzeStackDiff,PA as artifactKey,Ht as assertOriginGroupMethods,Mh as autocomplete,Rc as awsConfigManager,vc as backupManager,Vy as batch,sA as batchProcessingManager,Ic as blueGreenManager,aS as bounceComplaintHandler,KA as buildBunRuntimeLayerZip,Jp as buildCloudFormationTemplate,od as buildFailoverReplicaPolicyStatement,fu as buildMailEnv,jA as buildNodeRuntimeLayerZip,Gb as buildOptimizationManager,Ut as buildOriginGroup,Ju as buildOriginGroups,NC as buildPhpRuntimeLayerZip,ad as buildReplicationConfiguration,sd as buildReplicationRole,Dc as canaryManager,Zy as categorizeChanges,Mb as certificateManager,Sy as checkIAMPermissions,hs as checkInvocation,Ty as checkServiceQuotas,Yo as chunk,zg as clearSigningKeyCache,ec as cloudConfigSchema,Pc as cloudTrailManager,Zl as collectPhpAppEntries,Og as composePresets,MA as composeServerlessAppTemplate,$c as containerRegistryManager,ug as createApiBackendPreset,Nl as createCliHandler,ny as createCredentialProvider,Ng as createDashboardSite,Ag as createDataPipelinePreset,Xr as createError,og as createExistingStaticFullStackPreset,cg as createFullStackAppPreset,rC as createHandlers,wl as createHttpHandler,gg as createJamstackPreset,Eg as createLaravelPreset,vg as createMLApiPreset,hg as createMicroservicesPreset,dh as createMockAWS,eg as createNodeJsServerPreset,ng as createNodeJsServerlessPreset,$g as createPreset,Wr as createPresignedUrl,Hg as createPresignedUrlAsync,Dl as createQueueHandler,bg as createRealtimeAppPreset,Oo as createS3Client,Ig as createServerlessLaravelPreset,ig as createServerlessNodePreset,Zp as createStaticSitePreset,Rg as createTraditionalWebAppPreset,mg as createWordPressPreset,fe as createZip,Yh as crossRegionReferenceManager,Ib as databaseUserManager,oi as defaultLocalConfig,du as deploymentCoexistenceError,co as deriveManagementDashboardPort,Yn as detectDeploymentTargets,gy as detectMisconfigurations,Gr as detectServiceRegion,Qy as diffTemplates,rA as dlqMonitoringManager,nS as dnssecManager,Tc as drManager,cS as emailAnalyticsManager,mS as emailTemplateManager,El as eventToRequest,Br as extendPreset,tA as fifoQueueManager,_y as findChangedFiles,Ef as formatAccountStructure,Th as formatBytes,_u as formatDiff,Rh as formatDuration,Oh as formatFlagSuggestions,_h as formatHistory,Wh as formatHistoryStats,Eh as formatKeyValue,Ph as formatList,vh as formatProgressBar,Ac as formatRegion,df as formatRegionList,Dh as formatSuggestion,Ah as formatTable,Ch as formatTree,Co as fromEC2Metadata,vo as fromECSMetadata,bo as fromEnvironment,So as fromSharedCredentials,To as fromWebIdentity,yl as functionFingerprint,BA as generateAppImageDockerfile,Kf as generateApprovalConfig,Yi as generateBootstrap,rc as generateCleanupWorkflow,ic as generateCostReportWorkflow,Rf as generateCrossAccountRoleCF,Uf as generateDeploymentConfig,Bf as generateDeploymentPipeline,xf as generateDeploymentWorkflow,h as generateLogicalId,Wf as generateManualPipeline,Of as generateMatrixWorkflow,Hf as generateMultiEnvConfig,Ff as generateMultiEnvPipeline,kf as generateMultiEnvWorkflow,Mf as generatePRPreviewWorkflow,qf as generateParallelConfig,Ss as generatePhpFpmConfig,es as generatePhpLayerDockerfile,Gf as generatePreviewPipeline,nc as generatePreviewWorkflow,S as generateResourceName,jf as generateScheduledConfig,_f as generateScheduledPipeline,Lf as generateScheduledWorkflow,Yr as getAccountId,nf as getAllRegions,cf as getClosestRegion,$h as getCommandUsage,xh as getContextualHelp,ct as getCredentials,Xy as getDeploymentStrategy,eh as getDiffStats,Jy as getDiffSummary,_o as getErrorDetails,dn as getLocalConfig,ch as getLocalCredentials,oh as getLocalEndpoint,lh as getLocalEnvVars,Ry as getQuotaUsageSummary,Tf as getRecommendedStructure,ut as getRegion,mf as getRegionStats,sf as getRegionsByCompliance,rf as getRegionsByLocation,af as getRegionsByPricingTier,Wo as getRequiredPermissions,Qg as getSigningKeyCacheSize,Eu as getTimestamp,Zh as globalResourceManager,Ec as guardDutyManager,mo as hasManagementDashboardSite,$y as hashBuffer,By as hashDirectory,ii as hashFile,Fy as hashManifest,si as hashString,JC as healthCheckManager,Bb as imageScanningManager,fl as inspectInvocation,Cl as installRecursionFetch,ys as invocationContext,Nh as isLikelyTypo,ah as isLocalDevelopment,po as isManagementDashboardSiteName,Jg as isNodeCryptoAvailable,or as isS3RestEndpoint,ou as isStateDirConfigured,cu as isStatePath,of as isValidRegion,Yg as isWebCryptoAvailable,qb as lambdaConcurrencyManager,Xb as lambdaDLQManager,Qb as lambdaDestinationsManager,Ub as lambdaLayersManager,Yb as lambdaVPCManager,jb as lambdaVersionsManager,CC as laravelServerlessEnvDefaults,kc as logsManager,Ws as mailEnabled,hu as mailFirewallPorts,De as makeAWSRequest,Kg as makeAWSRequestAsync,jg as makeAWSRequestOnce,Mr as managementDashboardSiteName,Ge as mergeInfrastructure,Sb as metricsManager,Tb as migrationManager,bf as multiAccountManager,Qh as multiRegionManager,ZC as networkSecurityManager,Sf as organizationManager,GC as packagePhpApp,EA as packageServerlessApp,un as parallel,Uy as parallelMap,Hy as parallelWithRetry,hl as parseChain,qg as parseJSONResponse,wt as parseXMLResponse,Eb as performanceManager,Wn as phpLayerBuildStage,ul as phpLayerPackages,jn as phpRuntimeLayerAssets,tc as previewManager,sc as previewNotifications,qy as processInChunks,xc as progressiveDeploymentManager,ms as propagationHeaders,oA as queueManagementManager,Gy as quickHash,ps as recursionBlockedResponse,Xh as regionPairManager,Lc as replicaManager,Yy as requiresReplacement,ZA as resetRecursionRuntime,nC as resolveApp,pu as resolveAppDatabase,Su as resolveCloudProvider,Ue as resolveCredentials,lo as resolveDashboardDomain,uo as resolveDashboardDomains,Lu as resolveDeployBucketName,uu as resolveDeploymentMode,ht as resolveFailoverStatusCodes,yu as resolveMailService,Mg as resolveManagementDashboardSite,go as resolveManagementDashboardSites,Be as resolveOriginConnection,Du as resolveProjectStackName,kA as resolveQueueNames,Xi as resolveQueues,Al as resolveRecursionConfig,Ro as resolveRegion,Ou as resolveServerlessAppStackName,$u as resolveServerlessArtifactBucketName,Xn as resolveServerlessAssetBucketName,Zi as resolveServerlessRuntime,ku as resolveSiteBucketName,xu as resolveSiteResourceName,Nu as resolveSiteStackName,Gs as resolveStatePath,Mu as resolveStorageBucketName,rd as resolveStorageFailover,ev as resourceManagementManager,bs as responseToResult,iS as route53ResolverManager,Fc as route53RoutingManager,sl as runBuildHooks,Yl as runPhpBuildHooks,id as s3RegionalDomain,wu as sanitizeName,kh as searchCommands,Oc as secretsManager,Nb as secretsRotationManager,wc as securityHubManager,Ob as securityScanningManager,uS as senderReputationManager,jy as sequence,Bc as serviceMeshManager,au as setStateDir,al as sha256,vl as sharedRecursionGuard,ss as sharedRuntimeLoop,V as signRequest,_r as signRequestAsync,ef as stackDependencyManager,$e as stateDir,Jn as statePath,qC as staticSiteManager,Xl as storageAdvancedManager,cd as storageFailoverReplicasFromTemplate,pi as suggestCommand,Lh as suggestFlags,Ay as suggestIAMPolicy,Py as suggestQuotaIncrease,uf as suggestRegionPairs,lf as suggestRegions,Mc as syntheticsManager,Ho as templateCache,Pf as validateAccountStructure,ih as validateAgainstSchema,Bh as validateCommand,py as validateConfiguration,by as validateCredentials,cr as validateOriginGroups,na as validateResourceLimits,js as validateTemplate,ta as validateTemplateSize,Wg as withCDN,_g as withCache,Gg as withDatabase,fs as withInvocation,Bg as withMonitoring,Vg as withQueue,Fg as withSecurity,Ky as withTimeout,fb as xrayManager};
|