@stacksjs/ts-cloud 0.16.30 → 0.16.32
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/aws/index.js +1 -1
- package/dist/bin/{chunk-5nf3fxgw.js → chunk-12j17qm5.js} +1 -1
- package/dist/bin/{chunk-0n0jscsr.js → chunk-24473jks.js} +1 -1
- package/dist/bin/chunk-3932p1z3.js +1 -0
- package/dist/bin/chunk-3eztnxgw.js +1 -0
- package/dist/bin/{chunk-10sypz59.js → chunk-4182gadf.js} +1 -1
- package/dist/bin/chunk-4er4ktcs.js +1 -0
- package/dist/bin/{chunk-7577ykbj.js → chunk-6wz04wnk.js} +1 -1
- package/dist/bin/{chunk-remzfbhd.js → chunk-6yr12f64.js} +3 -3
- package/dist/bin/{chunk-8c4fnga8.js → chunk-79sd00d1.js} +1 -1
- package/dist/bin/{chunk-bkzt5ntz.js → chunk-81mt497w.js} +1 -1
- package/dist/bin/{chunk-dmyr6etw.js → chunk-8mgwqpmx.js} +1 -1
- package/dist/bin/{chunk-e6xn8g28.js → chunk-985ev3ns.js} +1 -1
- package/dist/bin/{chunk-bvtpvstn.js → chunk-9e62z9je.js} +11 -11
- package/dist/bin/{chunk-g1krw34t.js → chunk-9eq18gds.js} +1 -1
- package/dist/bin/chunk-9zhp2z0s.js +1 -0
- package/dist/bin/{chunk-g00a221j.js → chunk-b9psp74n.js} +14 -14
- package/dist/bin/chunk-bmmr5mq6.js +1 -0
- package/dist/bin/{chunk-je602ntp.js → chunk-cr56pxpt.js} +1 -1
- package/dist/bin/chunk-dvv2z19r.js +1 -0
- package/dist/bin/{chunk-y9cdqk8c.js → chunk-efbmb8rw.js} +1 -1
- package/dist/bin/chunk-eyrmv6c4.js +1 -0
- package/dist/bin/{chunk-9nnfyqme.js → chunk-f7dtn45y.js} +3 -3
- package/dist/bin/chunk-fnnv0t66.js +1 -0
- package/dist/bin/{chunk-1chq0c2k.js → chunk-fpxb97q5.js} +1 -1
- package/dist/bin/chunk-fwmje99n.js +1 -0
- package/dist/bin/{chunk-k8r5zfnf.js → chunk-gcm9n6ww.js} +1 -1
- package/dist/bin/{chunk-6hrycgbh.js → chunk-gzxpkk0c.js} +1 -1
- package/dist/bin/{chunk-s3mv4z3f.js → chunk-jhp53qsd.js} +1 -1
- package/dist/bin/{chunk-jeg6vw5v.js → chunk-jzby2kzy.js} +1 -1
- package/dist/bin/{chunk-xtqx4v3f.js → chunk-kgtzvh2k.js} +1 -1
- package/dist/bin/{chunk-a9yp82q5.js → chunk-kqf19j9m.js} +1 -1
- package/dist/bin/{chunk-nb5vjsdg.js → chunk-mpq5ct10.js} +4 -4
- package/dist/bin/chunk-n775dk3f.js +1 -0
- package/dist/bin/{chunk-kne9dmwr.js → chunk-nnawqw34.js} +32 -32
- package/dist/bin/chunk-ppj604c9.js +1 -0
- package/dist/bin/chunk-prq5gw4j.js +1 -0
- package/dist/bin/chunk-pt71fyem.js +1 -0
- package/dist/bin/{chunk-1wtkv65w.js → chunk-py8cvqvx.js} +1 -1
- package/dist/bin/{chunk-3ykx59eg.js → chunk-q6z8wvvb.js} +1 -1
- package/dist/bin/{chunk-q9tvzcr7.js → chunk-qe56mnjc.js} +3 -3
- package/dist/bin/chunk-qvj454fy.js +1 -0
- package/dist/bin/{chunk-j8dkatkk.js → chunk-sdy79wz7.js} +4 -4
- package/dist/bin/chunk-smj97rs5.js +1 -0
- package/dist/bin/{chunk-yrq5bkxe.js → chunk-tg45thhb.js} +1 -1
- package/dist/bin/{chunk-e4p6hwct.js → chunk-tgwx5haz.js} +1 -1
- package/dist/bin/{chunk-9p7g25kx.js → chunk-vhz2wmb8.js} +81 -81
- package/dist/bin/{chunk-a1kpwbjg.js → chunk-wt7wjgcr.js} +3 -3
- package/dist/bin/{chunk-j2yy3tth.js → chunk-x56s9b7f.js} +1 -1
- package/dist/bin/chunk-yf3zys06.js +1 -0
- package/dist/bin/{chunk-ee6ssn26.js → chunk-zhkbdsfs.js} +1 -1
- package/dist/bin/{chunk-jf8jp6f5.js → chunk-zk3nm0td.js} +1 -1
- package/dist/bin/chunk-zmjm7bmm.js +1 -0
- package/dist/bin/cli.js +46 -46
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/chunk-05bmq0z1.js +1 -0
- package/dist/chunk-0qdgw73b.js +1 -0
- package/dist/{chunk-75bga11p.js → chunk-2mw7bjhn.js} +1 -1
- package/dist/{chunk-92w1g5d9.js → chunk-4hdp9ms2.js} +1 -1
- package/dist/{chunk-m3a4brpj.js → chunk-4jgy95bv.js} +5 -5
- package/dist/{chunk-z8qz33yk.js → chunk-57fhsqzb.js} +2 -2
- package/dist/{chunk-3kpnn06d.js → chunk-983txhkg.js} +1 -1
- package/dist/{chunk-b6ar7eqc.js → chunk-efssa93f.js} +1 -1
- package/dist/{chunk-26cq0zjv.js → chunk-jh38v9zp.js} +2 -2
- package/dist/{chunk-f733qy2d.js → chunk-kavwrxm8.js} +2 -2
- package/dist/{chunk-9n0q2cxj.js → chunk-nq51dyxz.js} +4 -4
- package/dist/{chunk-h3kkh31v.js → chunk-peeqkk92.js} +81 -81
- package/dist/chunk-pf6sanwe.js +1 -0
- package/dist/{chunk-2c8pcbq8.js → chunk-r45340yc.js} +34 -34
- package/dist/{chunk-mqm1hxaw.js → chunk-rqe0sfqw.js} +2 -2
- package/dist/{chunk-1erk1r1m.js → chunk-s909414m.js} +1 -1
- package/dist/{chunk-t3yzfbe7.js → chunk-t1gts5j9.js} +4 -4
- package/dist/{chunk-yc2rm4v9.js → chunk-wbabf3hg.js} +1 -1
- package/dist/{chunk-aeqm2v91.js → chunk-xbh2vr95.js} +34 -34
- package/dist/deploy/index.js +1 -1
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/shared/deploy-script.d.ts +67 -0
- package/dist/index.js +3 -3
- package/dist/operations/index.js +1 -1
- package/dist/protection/index.js +1 -1
- package/dist/spend/index.js +1 -1
- package/dist/ui/404.html +1 -1
- package/dist/ui/accept-invitation.html +1 -1
- package/dist/ui/access-denied.html +1 -1
- package/dist/ui/account/automation.html +6 -6
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +6 -6
- package/dist/ui/applications/new.html +2 -2
- package/dist/ui/data/backups.html +6 -6
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +6 -6
- package/dist/ui/integrations.html +1 -1
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +6 -6
- package/dist/ui/operations/jobs.html +6 -6
- package/dist/ui/operations/maintenance.html +6 -6
- package/dist/ui/operations/observability.html +6 -6
- package/dist/ui/operations/previews.html +5 -5
- package/dist/ui/operations/queue.html +6 -6
- package/dist/ui/operations/regions.html +6 -6
- package/dist/ui/operations/releases.html +6 -6
- package/dist/ui/operations/spend.html +6 -6
- package/dist/ui/operations/workloads.html +6 -6
- package/dist/ui/security.html +1 -1
- package/dist/ui/server/actions.html +6 -6
- package/dist/ui/server/activity.html +1 -1
- package/dist/ui/server/capacity.html +6 -6
- package/dist/ui/server/database.html +6 -6
- package/dist/ui/server/deployments.html +6 -6
- package/dist/ui/server/diagnostics.html +2 -2
- package/dist/ui/server/firewall.html +6 -6
- package/dist/ui/server/fleet.html +6 -6
- package/dist/ui/server/logs.html +6 -6
- package/dist/ui/server/metrics.html +6 -6
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +2 -2
- package/dist/ui/server/sites.html +6 -6
- package/dist/ui/server/ssh-keys.html +6 -6
- package/dist/ui/server/team.html +6 -6
- package/dist/ui/server/terminal.html +2 -2
- package/dist/ui/serverless/alarms.html +6 -6
- package/dist/ui/serverless/assets.html +1 -1
- package/dist/ui/serverless/cost.html +1 -1
- package/dist/ui/serverless/data.html +5 -5
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +2 -2
- package/dist/ui/serverless/functions.html +6 -6
- package/dist/ui/serverless/logs.html +6 -6
- package/dist/ui/serverless/metrics.html +2 -2
- package/dist/ui/serverless/queues.html +6 -6
- package/dist/ui/serverless/secrets.html +6 -6
- package/dist/ui/serverless/traces.html +6 -6
- package/dist/ui/serverless.html +5 -5
- package/package.json +3 -3
- package/dist/bin/chunk-052sk11z.js +0 -1
- package/dist/bin/chunk-1d4663e1.js +0 -1
- package/dist/bin/chunk-223yq2z0.js +0 -1
- package/dist/bin/chunk-675txngy.js +0 -1
- package/dist/bin/chunk-98e48n5j.js +0 -1
- package/dist/bin/chunk-ckmgwd81.js +0 -1
- package/dist/bin/chunk-ecxchy9q.js +0 -1
- package/dist/bin/chunk-gcazbfsv.js +0 -1
- package/dist/bin/chunk-gg6vwdnn.js +0 -1
- package/dist/bin/chunk-gz0gahzh.js +0 -1
- package/dist/bin/chunk-hdkxj8p9.js +0 -1
- package/dist/bin/chunk-hg60j47r.js +0 -1
- package/dist/bin/chunk-jxh78anm.js +0 -1
- package/dist/bin/chunk-mv0t7j76.js +0 -1
- package/dist/bin/chunk-p8f1qgz2.js +0 -1
- package/dist/bin/chunk-pa106cr4.js +0 -1
- package/dist/bin/chunk-w3815pxd.js +0 -1
- package/dist/chunk-43pe4shw.js +0 -1
- package/dist/chunk-94tb2msg.js +0 -1
- package/dist/chunk-d8wcqgpx.js +0 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import{createRequire as Tr}from"node:module";import{isAbsolute as Ot,join as mt,relative as Mr}from"node:path";import{existsSync as Ge,readdirSync as Qr}from"node:fs";import{join as le}from"node:path";import{createHash as hn}from"node:crypto";import{copyFileSync as yn,existsSync as Rt,readdirSync as fn,readFileSync as at,statSync as Sn,writeFileSync as nt}from"node:fs";import{basename as bn,dirname as Ma,extname as Oa,join as je}from"node:path";import{existsSync as nr,readFileSync as Kt}from"node:fs";import{homedir as ir}from"node:os";import{join as sr}from"node:path";import{createHash as or}from"node:crypto";import{existsSync as st,mkdirSync as Pi,readdirSync as Wa,readFileSync as Ga,unlinkSync as Ke,writeFileSync as Ri}from"node:fs";import{join as Dt}from"node:path";import{createHash as Qt}from"node:crypto";import{createReadStream as Ni,readdirSync as Di,statSync as gt}from"node:fs";import{join as ki,relative as $i}from"node:path";import{deflateRawSync as Ui}from"node:zlib";import{execSync as Hi}from"node:child_process";import{createHash as zi}from"node:crypto";import{cpSync as Qi,mkdtempSync as Ji,rmSync as Yi,writeFileSync as Zi}from"node:fs";import{tmpdir as Xi}from"node:os";import{dirname as es,isAbsolute as ts,join as be,resolve as as}from"node:path";import{fileURLToPath as rs}from"node:url";import{execFileSync as St}from"node:child_process";import{mkdtempSync as ur,readFileSync as bt,rmSync as dr}from"node:fs";import{tmpdir as mr}from"node:os";import{dirname as os,join as de}from"node:path";import{fileURLToPath as cs}from"node:url";import{AsyncLocalStorage as us}from"node:async_hooks";import{createHash as ds}from"node:crypto";import{readFileSync as fs}from"node:fs";import{dirname as Ss,join as fr}from"node:path";import{fileURLToPath as bs}from"node:url";import{execFileSync as ot}from"node:child_process";import{existsSync as Cs,mkdirSync as vs,mkdtempSync as Ts,readdirSync as ws,readFileSync as Es,rmSync as Ps,statSync as Sr,writeFileSync as Is}from"node:fs";import{tmpdir as Rs}from"node:os";import{join as Pe,relative as Ns}from"node:path";import{execSync as Ds}from"node:child_process";import{createHash as ks}from"node:crypto";import{readdirSync as $s,readFileSync as Ls,statSync as Ar}from"node:fs";import{join as Ms,relative as Cr,resolve as La}from"node:path";var wr=Object.defineProperty,Er=(e)=>e;function Ir(e,a){this[e]=Er.bind(null,a)}var Le=(e,a)=>{for(var r in a)wr(e,r,{get:a[r],enumerable:!0,configurable:!0,set:Ir.bind(a,r)})},Rr=(e,a,r)=>()=>{if(e)try{a=e(e=0)}catch(n){r=[n]}if(r)throw r[0];return a},kr=Tr(import.meta.url);function hc(e){let a=typeof e==="string"?new URL(e):e,{hostname:r,pathname:n}=a;if(r.endsWith(".on.aws")){let u=r.match(/^[^.]+\.lambda-url\.([^.]+)\.on\.aws$/);if(u)return{service:"lambda",region:u[1]};return{service:"",region:""}}if(r.endsWith(".r2.cloudflarestorage.com"))return{service:"s3",region:"auto"};if(r.endsWith(".backblazeb2.com")){let u=r.match(/^(?:[^.]+\.)?s3\.([^.]+)\.backblazeb2\.com$/);if(u)return{service:"s3",region:u[1]};return{service:"",region:""}}let i=r.replace("dualstack.","").match(/([^.]+)\.(?:([^.]+)\.)?amazonaws\.com(?:\.cn)?$/);if(!i)return{service:"",region:""};let o=i[1],c=i[2]||"";if(c==="us-gov")c="us-gov-west-1";else if(c==="s3"||c==="s3-accelerate")c="us-east-1",o="s3";else if(o==="iot")if(r.startsWith("iot."))o="execute-api";else if(r.startsWith("data.jobs.iot."))o="iot-jobs-data";else o=n==="/mqtt"?"iotdevicegateway":"iotdata";else if(o==="autoscaling");else if(!c&&o.startsWith("s3-"))c=o.slice(3).replace(/^fips-|^external-1/,""),o="s3";else if(o.endsWith("-fips"))o=o.slice(0,-5);else if(c&&/-\d$/.test(o)&&!/-\d$/.test(c))[o,c]=[c,o];return o=Ja[o]||o,{service:o,region:c||"us-east-1"}}function ae(e){let{method:a,url:r,body:n="",accessKeyId:i,secretAccessKey:o,sessionToken:c,signQuery:u=!1,expiresIn:d=86400,datetime:m}=e,p=new URL(r),g=p.hostname,h=hc(p),y=e.service||h.service,f=e.region||h.region;if(!y)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!f)throw Error("Could not detect region from URL. Please provide region explicitly.");let b=m||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),
|
|
2
|
-
`),U=He(_),Y=[I,b,
|
|
3
|
-
`),q=e.cache??fe,Q=qa(o,
|
|
4
|
-
`),Y=await lt(U),q=[I,b,
|
|
5
|
-
`),Q=e.cache??fe,V=await Ha(o,
|
|
6
|
-
`,N=yt(b.searchParams),R=[r,I,N,
|
|
1
|
+
import{createRequire as Tr}from"node:module";import{isAbsolute as Ot,join as mt,relative as Mr}from"node:path";import{existsSync as Ge,readdirSync as Qr}from"node:fs";import{join as le}from"node:path";import{createHash as hn}from"node:crypto";import{copyFileSync as yn,existsSync as Rt,readdirSync as fn,readFileSync as at,statSync as Sn,writeFileSync as nt}from"node:fs";import{basename as bn,dirname as Ma,extname as Oa,join as je}from"node:path";import{existsSync as nr,readFileSync as Kt}from"node:fs";import{homedir as ir}from"node:os";import{join as sr}from"node:path";import{createHash as or}from"node:crypto";import{existsSync as st,mkdirSync as Pi,readdirSync as Wa,readFileSync as Ga,unlinkSync as Ke,writeFileSync as Ri}from"node:fs";import{join as Dt}from"node:path";import{createHash as Qt}from"node:crypto";import{createReadStream as Ni,readdirSync as Di,statSync as gt}from"node:fs";import{join as ki,relative as $i}from"node:path";import{deflateRawSync as Ui}from"node:zlib";import{execSync as Hi}from"node:child_process";import{createHash as zi}from"node:crypto";import{cpSync as Qi,mkdtempSync as Ji,rmSync as Yi,writeFileSync as Zi}from"node:fs";import{tmpdir as Xi}from"node:os";import{dirname as es,isAbsolute as ts,join as be,resolve as as}from"node:path";import{fileURLToPath as rs}from"node:url";import{execFileSync as St}from"node:child_process";import{mkdtempSync as ur,readFileSync as bt,rmSync as dr}from"node:fs";import{tmpdir as mr}from"node:os";import{dirname as os,join as de}from"node:path";import{fileURLToPath as cs}from"node:url";import{AsyncLocalStorage as us}from"node:async_hooks";import{createHash as ds}from"node:crypto";import{readFileSync as fs}from"node:fs";import{dirname as Ss,join as fr}from"node:path";import{fileURLToPath as bs}from"node:url";import{execFileSync as ot}from"node:child_process";import{existsSync as Cs,mkdirSync as vs,mkdtempSync as Ts,readdirSync as ws,readFileSync as Es,rmSync as Ps,statSync as Sr,writeFileSync as Is}from"node:fs";import{tmpdir as Rs}from"node:os";import{join as Pe,relative as Ns}from"node:path";import{execSync as Ds}from"node:child_process";import{createHash as ks}from"node:crypto";import{readdirSync as $s,readFileSync as Ls,statSync as Ar}from"node:fs";import{join as Ms,relative as Cr,resolve as La}from"node:path";var wr=Object.defineProperty,Er=(e)=>e;function Ir(e,a){this[e]=Er.bind(null,a)}var Le=(e,a)=>{for(var r in a)wr(e,r,{get:a[r],enumerable:!0,configurable:!0,set:Ir.bind(a,r)})},Rr=(e,a,r)=>()=>{if(e)try{a=e(e=0)}catch(n){r=[n]}if(r)throw r[0];return a},kr=Tr(import.meta.url);function hc(e){let a=typeof e==="string"?new URL(e):e,{hostname:r,pathname:n}=a;if(r.endsWith(".on.aws")){let u=r.match(/^[^.]+\.lambda-url\.([^.]+)\.on\.aws$/);if(u)return{service:"lambda",region:u[1]};return{service:"",region:""}}if(r.endsWith(".r2.cloudflarestorage.com"))return{service:"s3",region:"auto"};if(r.endsWith(".backblazeb2.com")){let u=r.match(/^(?:[^.]+\.)?s3\.([^.]+)\.backblazeb2\.com$/);if(u)return{service:"s3",region:u[1]};return{service:"",region:""}}let i=r.replace("dualstack.","").match(/([^.]+)\.(?:([^.]+)\.)?amazonaws\.com(?:\.cn)?$/);if(!i)return{service:"",region:""};let o=i[1],c=i[2]||"";if(c==="us-gov")c="us-gov-west-1";else if(c==="s3"||c==="s3-accelerate")c="us-east-1",o="s3";else if(o==="iot")if(r.startsWith("iot."))o="execute-api";else if(r.startsWith("data.jobs.iot."))o="iot-jobs-data";else o=n==="/mqtt"?"iotdevicegateway":"iotdata";else if(o==="autoscaling");else if(!c&&o.startsWith("s3-"))c=o.slice(3).replace(/^fips-|^external-1/,""),o="s3";else if(o.endsWith("-fips"))o=o.slice(0,-5);else if(c&&/-\d$/.test(o)&&!/-\d$/.test(c))[o,c]=[c,o];return o=Ja[o]||o,{service:o,region:c||"us-east-1"}}function ae(e){let{method:a,url:r,body:n="",accessKeyId:i,secretAccessKey:o,sessionToken:c,signQuery:u=!1,expiresIn:d=86400,datetime:m}=e,p=new URL(r),g=p.hostname,h=hc(p),y=e.service||h.service,f=e.region||h.region;if(!y)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!f)throw Error("Could not detect region from URL. Please provide region explicitly.");let b=m||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),v=b.substring(0,8),T=[v,f,y,"aws4_request"].join("/"),I="AWS4-HMAC-SHA256";if(u)return $r({urlObj:p,method:a,body:n,accessKeyId:i,secretAccessKey:o,sessionToken:c,service:y,region:f,timestamp:b,date:v,credentialScope:T,algorithm:I,expiresIn:d,cache:e.cache});let C=p.pathname||"/",N=yt(p.searchParams),R={host:g,"x-amz-date":b,...e.headers};if(c)R["x-amz-security-token"]=c;let k=Object.keys(R).some((me)=>me.toLowerCase()==="content-type");if(n&&!k)R["content-type"]="application/x-amz-json-1.0";if(y==="s3"&&!R["x-amz-content-sha256"])R["x-amz-content-sha256"]=He(n);let x=Va(R),M=ja(R),B=R["x-amz-content-sha256"]||He(n),_=[a,ft(C),N,x,M,B].join(`
|
|
2
|
+
`),U=He(_),Y=[I,b,T,U].join(`
|
|
3
|
+
`),q=e.cache??fe,Q=qa(o,v,f,y,Y,q),V=[`${I} Credential=${i}/${T}`,`SignedHeaders=${M}`,`Signature=${Q}`].join(", ");return R.authorization=V,{url:r,method:a,headers:R,body:n||void 0}}async function yc(e){let{method:a,url:r,body:n="",accessKeyId:i,secretAccessKey:o,sessionToken:c,signQuery:u=!1,expiresIn:d=86400,datetime:m}=e,p=new URL(r),g=p.hostname,h=hc(p),y=e.service||h.service,f=e.region||h.region;if(!y)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!f)throw Error("Could not detect region from URL. Please provide region explicitly.");let b=m||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),v=b.substring(0,8),T=[v,f,y,"aws4_request"].join("/"),I="AWS4-HMAC-SHA256";if(u)return Lr({urlObj:p,method:a,body:n,accessKeyId:i,secretAccessKey:o,sessionToken:c,service:y,region:f,timestamp:b,date:v,credentialScope:T,algorithm:I,expiresIn:d,cache:e.cache});let C=p.pathname||"/",N=yt(p.searchParams),R={host:g,"x-amz-date":b,...e.headers};if(c)R["x-amz-security-token"]=c;let k=Object.keys(R).some((Me)=>Me.toLowerCase()==="content-type");if(n&&!k)R["content-type"]="application/x-amz-json-1.0";let x=await lt(n);if(y==="s3"&&!R["x-amz-content-sha256"])R["x-amz-content-sha256"]=x;let M=Va(R),B=ja(R),_=R["x-amz-content-sha256"]||x,U=[a,ft(C),N,M,B,_].join(`
|
|
4
|
+
`),Y=await lt(U),q=[I,b,T,Y].join(`
|
|
5
|
+
`),Q=e.cache??fe,V=await Ha(o,v,f,y,q,Q),me=[`${I} Credential=${i}/${T}`,`SignedHeaders=${B}`,`Signature=${V}`].join(", ");return R.authorization=me,{url:r,method:a,headers:R,body:n||void 0}}function $r(e){let{urlObj:a,method:r,body:n,accessKeyId:i,secretAccessKey:o,sessionToken:c,service:u,region:d,timestamp:m,date:p,credentialScope:g,algorithm:h,expiresIn:y,cache:f}=e,b=new URL(a.toString());b.searchParams.set("X-Amz-Algorithm",h),b.searchParams.set("X-Amz-Credential",`${i}/${g}`),b.searchParams.set("X-Amz-Date",m),b.searchParams.set("X-Amz-Expires",String(y));let v=u==="s3"?"UNSIGNED-PAYLOAD":He(n);if(u==="s3")b.searchParams.set("X-Amz-Content-Sha256",v);let T="host";if(b.searchParams.set("X-Amz-SignedHeaders",T),c)b.searchParams.set("X-Amz-Security-Token",c);let I=ft(b.pathname||"/"),C=`host:${b.hostname}
|
|
6
|
+
`,N=yt(b.searchParams),R=[r,I,N,C,T,v].join(`
|
|
7
7
|
`),k=[h,m,g,He(R)].join(`
|
|
8
|
-
`),x=qa(o,p,d,u,k,f??fe);return b.searchParams.set("X-Amz-Signature",x),{url:b.toString(),method:r,headers:{},body:n||void 0}}async function Lr(e){let{urlObj:a,method:r,body:n,accessKeyId:i,secretAccessKey:o,sessionToken:c,service:u,region:d,timestamp:m,date:p,credentialScope:g,algorithm:h,expiresIn:y,cache:f}=e,b=new URL(a.toString());b.searchParams.set("X-Amz-Algorithm",h),b.searchParams.set("X-Amz-Credential",`${i}/${g}`),b.searchParams.set("X-Amz-Date",m),b.searchParams.set("X-Amz-Expires",String(y));let
|
|
9
|
-
`,N=yt(b.searchParams),R=[r,I,N,
|
|
8
|
+
`),x=qa(o,p,d,u,k,f??fe);return b.searchParams.set("X-Amz-Signature",x),{url:b.toString(),method:r,headers:{},body:n||void 0}}async function Lr(e){let{urlObj:a,method:r,body:n,accessKeyId:i,secretAccessKey:o,sessionToken:c,service:u,region:d,timestamp:m,date:p,credentialScope:g,algorithm:h,expiresIn:y,cache:f}=e,b=new URL(a.toString());b.searchParams.set("X-Amz-Algorithm",h),b.searchParams.set("X-Amz-Credential",`${i}/${g}`),b.searchParams.set("X-Amz-Date",m),b.searchParams.set("X-Amz-Expires",String(y));let v=u==="s3"?"UNSIGNED-PAYLOAD":await lt(n);if(u==="s3")b.searchParams.set("X-Amz-Content-Sha256",v);let T="host";if(b.searchParams.set("X-Amz-SignedHeaders",T),c)b.searchParams.set("X-Amz-Security-Token",c);let I=ft(b.pathname||"/"),C=`host:${b.hostname}
|
|
9
|
+
`,N=yt(b.searchParams),R=[r,I,N,C,T,v].join(`
|
|
10
10
|
`),k=[h,m,g,await lt(R)].join(`
|
|
11
11
|
`),x=await Ha(o,p,d,u,k,f??fe);return b.searchParams.set("X-Amz-Signature",x),{url:b.toString(),method:r,headers:{},body:n||void 0}}function Nd(e){let{url:a,method:r="GET",expiresIn:n=3600,...i}=e,o=Math.min(n,604800);return ae({...i,url:a,method:r,signQuery:!0,expiresIn:o}).url}async function bp(e){let{url:a,method:r="GET",expiresIn:n=3600,...i}=e,o=Math.min(n,604800);return(await yc({...i,url:a,method:r,signQuery:!0,expiresIn:o})).url}function Va(e){return Object.keys(e).sort().map((a)=>`${a.toLowerCase()}:${e[a].trim().replace(/\s+/g," ")}`).join(`
|
|
12
12
|
`)+`
|
|
13
|
-
`}function ja(e){return Object.keys(e).sort().map((a)=>a.toLowerCase()).join(";")}function yt(e){let a=[];return e.forEach((r,n)=>{a.push([Mt(n),Mt(r)])}),a.sort((r,n)=>{if(r[0]<n[0])return-1;if(r[0]>n[0])return 1;if(r[1]<n[1])return-1;if(r[1]>n[1])return 1;return 0}),a.map(([r,n])=>`${r}=${n}`).join("&")}function ft(e){return e.split("/").map((a)=>Mt(a)).join("/")}function Mt(e){return encodeURIComponent(e).replace(/[!'()*]/g,(a)=>`%${a.charCodeAt(0).toString(16).toUpperCase()}`)}function He(e){if(!$e)throw Error("Synchronous hash not available in browser. Use signRequestAsync() instead.");return $e.createHash("sha256").update(e,"utf8").digest("hex")}function xe(e,a){if(!$e)throw Error("Synchronous hmac not available in browser. Use signRequestAsync() instead.");return $e.createHmac("sha256",e).update(a,"utf8").digest()}async function lt(e){let a=new TextEncoder().encode(e),r=await crypto.subtle.digest("SHA-256",a);return Ka(new Uint8Array(r))}async function We(e,a){let r=new TextEncoder,n=typeof e==="string"?r.encode(e):e,i=r.encode(a),o=await crypto.subtle.importKey("raw",n.buffer,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),c=await crypto.subtle.sign("HMAC",o,i.buffer);return new Uint8Array(c)}function Ka(e){return Array.from(e).map((a)=>a.toString(16).padStart(2,"0")).join("")}function qa(e,a,r,n,i,o){let c=`${e}:${a}:${r}:${n}`,u=o.get(c);if(!u){let d=xe(`AWS4${e}`,a),m=xe(d,r),p=xe(m,n);if(u=xe(p,"aws4_request"),o.size>=Qa){let g=o.keys().next().value;if(g)o.delete(g)}o.set(c,u)}return xe(u,i).toString("hex")}async function Ha(e,a,r,n,i,o){let c=`${e}:${a}:${r}:${n}`,u=o.get(c);if(!u){let m=await We(`AWS4${e}`,a),p=await We(m,r),g=await We(p,n);if(u=await We(g,"aws4_request"),o.size>=Qa){let h=o.keys().next().value;if(h)o.delete(h)}o.set(c,u)}let d=await We(u,i);return Ka(d)}function za(e,a){return a.includes(e)}function ut(e,a,r){let n=a*Math.pow(2,e),i=Math.random()*0.3*n;return Math.min(n+i,r)}function dt(e){return new Promise((a)=>setTimeout(a,e))}async function hi(e,a){let{maxRetries:r=3,initialDelayMs:n=100,maxDelayMs:i=5000,retryableStatusCodes:o=[429,500,502,503,504],timeoutMs:c=30000}=a??{},u,d;for(let m=0;m<=r;m++){let p=ae(e),g={method:p.method,headers:p.headers};if(p.body)g.body=p.body;let h=new AbortController,y=setTimeout(()=>h.abort(),c);g.signal=h.signal;try{let f=await fetch(p.url,g);if(clearTimeout(y),d=f,f.ok)return f;if(m<r&&za(f.status,o)){let T=ut(m,n,i);await dt(T);continue}let b=await f.text();throw Error(`AWS API request failed (${f.status}): ${b}`)}catch(f){if(clearTimeout(y),u=f,f instanceof Error&&f.name==="AbortError")u=Error(`Request timed out after ${c}ms`);if(m<r&&!(f instanceof Error&&f.message.includes("AWS API request failed"))){let b=ut(m,n,i);await dt(b);continue}throw u}}throw u??Error("Request failed after retries")}async function vp(e){return hi(e,{maxRetries:0})}async function Tp(e,a){let{maxRetries:r=3,initialDelayMs:n=100,maxDelayMs:i=5000,retryableStatusCodes:o=[429,500,502,503,504],timeoutMs:c=30000}=a??{},u;for(let d=0;d<=r;d++){let m=await yc(e),p={method:m.method,headers:m.headers};if(m.body)p.body=m.body;let g=new AbortController,h=setTimeout(()=>g.abort(),c);p.signal=g.signal;try{let y=await fetch(m.url,p);if(clearTimeout(h),y.ok)return y;if(d<r&&za(y.status,o)){let b=ut(d,n,i);await dt(b);continue}let f=await y.text();throw Error(`AWS API request failed (${y.status}): ${f}`)}catch(y){if(clearTimeout(h),u=y,y instanceof Error&&y.name==="AbortError")u=Error(`Request timed out after ${c}ms`);if(d<r&&!(y instanceof Error&&y.message.includes("AWS API request failed"))){let f=ut(d,n,i);await dt(f);continue}throw u}}throw u??Error("Request failed after retries")}async function Ws(e){let a=await e.text(),r={},n=/<(\w+)>([^<]+)<\/\1>/g,i;while((i=n.exec(a))!==null){let[,o,c]=i;r[o]=c}return r}async function Ep(e){return await e.json()}function wp(){fe.clear()}function Cp(){return fe.size}function Ap(){return $e!==void 0}function Ip(){return typeof crypto<"u"&&typeof crypto.subtle<"u"}var $e,fe,Qa=100,Ja,Ye=Rr(async()=>{try{$e=await import("node:crypto")}catch{}fe=new Map,Ja={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"}}),Rp={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}},Pp={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}}}},Sc=".ts-cloud",bc="TS_CLOUD_STATE_DIR",Gt=null;function Gs(e){Gt=e?.trim()||null}function Ks(){return Boolean(process.env[bc]?.trim()||Gt)}function Ao(){return process.env[bc]?.trim()||Gt||Sc}function et(...e){return mt(Ao(),...e)}function A(e,...a){let r=Ao();return Ot(r)?mt(r,...a):mt(e,r,...a)}function Js(e,a=process.cwd()){let r=(i,o)=>{let c=Mr(i,o);return c===""||!c.startsWith("..")&&!Ot(c)},n=Ot(e)?e:mt(a,e);return r(A(a),n)}function vc(e){let a=e.infrastructure?.compute!=null,r=Object.values(e.environments??{}).some((n)=>n?.app!=null);return{server:a,serverless:r}}function H(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:a}=vc(e);return a?"serverless":"server"}function Pr(e){let{server:a,serverless:r}=vc(e);if(a&&r)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"&&r&&!a)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&a&&!r)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function C(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function Or(e){return typeof e==="object"&&e!==null?e:{}}function Dd(e){return e===!0||typeof e==="object"&&e!==null}function xr(e,a){let r=a?e.environments?.[a]:void 0;if(r?.domain)return r.domain;let n=Object.values(e.sites??{}),i=e.sites?.main?.domain??n.find((o)=>o.domain)?.domain;if(i)return i;return`${e.project?.slug??"app"}.local`}function Br(e){let a=e.indexOf(".");return a>0?e.slice(a+1):void 0}function yi(e,a={}){let r=e.infrastructure?.compute?.managedServices?.mail,n=Or(r),i=a.environmentType??(a.environment?e.environments?.[a.environment]?.type:void 0),o=n.mode??(i==="production"?"server":"catcher"),c=o==="server",u=xr(e,a.environment),d=n.hostname??(c?`mail.${u}`:"localhost"),m=n.ports??{},p=c?{smtp:m.smtp??25,submission:m.submission??587,submissions:m.submissions??465,imap:m.imap??143,imaps:m.imaps??993,webmail:m.webmail??8080,managesieve:m.managesieve}:{smtp:m.smtp??1025,submission:m.submission,submissions:m.submissions,imap:m.imap,imaps:m.imaps,webmail:m.webmail??8025,managesieve:m.managesieve},g=n.tls??{},h=g.enabled??c,y=!!(g.certPath&&g.keyPath),f=(n.accounts??[]).map((M)=>({address:M.address,password:M.password})),b=typeof n.dkim==="object"&&n.dkim!==null?n.dkim:{},T=n.dkim===!1?!1:n.dkim===!0||c,w=typeof n.webmail==="object"&&n.webmail!==null?n.webmail:{},I=n.webmail===!1?!1:w.enabled??!0,v=n.spam??{},N=n.delivery??(c?"direct":"none"),R=n.expose??c,k=Br(d),x=[...new Set([d,...k?[k]:[],...n.domains??[]])];return{enabled:Dd(r),mode:o,version:n.version,hostname:d,domains:x,ports:p,tls:{enabled:h,acme:h&&!y&&(g.acme??!0),certPath:g.certPath,keyPath:g.keyPath,requireForAuth:g.requireForAuth??(h&&c),acmeEmail:g.acmeEmail??f[0]?.address},dkim:{enabled:T,selector:b.selector??"default",rotate:b.rotate??!1,rotateIntervalDays:b.rotateIntervalDays??90},webmail:{enabled:I,port:w.port??p.webmail,domain:w.domain},delivery:N,sesRegion:n.sesRegion??"us-east-1",accounts:f,storagePath:n.storagePath??"/var/lib/mail",maxMessageSize:n.maxMessageSize??26214400,spam:{enabled:v.enabled??c,enforce:v.enforce??!1,junkScore:v.junkScore??5,rejectScore:v.rejectScore??12,dnsbl:v.dnsbl??c,greylist:v.greylist??!1},webhookUrl:n.webhookUrl,expose:R,bindAddress:R?"0.0.0.0":"127.0.0.1"}}function Xs(e){if(!e.enabled||!e.expose)return[];let a=[e.ports.smtp,e.ports.submission,e.ports.submissions,e.ports.imap,e.ports.imaps,e.ports.managesieve].filter((r)=>typeof r==="number");if(e.webmail.enabled&&!e.webmail.domain)a.push(e.webmail.port);return[...new Set(a)].sort((r,n)=>r-n)}function Qs(e){if(!e.enabled)return{};let a=e.ports.submission??e.ports.smtp,r={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(a)};if(e.mode==="server"){r.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let n=e.accounts[0];if(n)r.MAIL_USERNAME=n.address,r.MAIL_PASSWORD=n.password}else r.MAIL_ENCRYPTION="null",r.MAIL_USERNAME="null",r.MAIL_PASSWORD="null";return r}function F(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 Io{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,a){return this.template.Resources[e]=a,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,a){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=a,this}addOutput(e,a){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=a,this}addMetadata(e,a){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[e]=a,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,a=0){let r=" ".repeat(a),n="";for(let[i,o]of Object.entries(e)){if(o===null||o===void 0)continue;if(typeof o==="object"&&!Array.isArray(o))n+=`${r}${i}:
|
|
13
|
+
`}function ja(e){return Object.keys(e).sort().map((a)=>a.toLowerCase()).join(";")}function yt(e){let a=[];return e.forEach((r,n)=>{a.push([Mt(n),Mt(r)])}),a.sort((r,n)=>{if(r[0]<n[0])return-1;if(r[0]>n[0])return 1;if(r[1]<n[1])return-1;if(r[1]>n[1])return 1;return 0}),a.map(([r,n])=>`${r}=${n}`).join("&")}function ft(e){return e.split("/").map((a)=>Mt(a)).join("/")}function Mt(e){return encodeURIComponent(e).replace(/[!'()*]/g,(a)=>`%${a.charCodeAt(0).toString(16).toUpperCase()}`)}function He(e){if(!$e)throw Error("Synchronous hash not available in browser. Use signRequestAsync() instead.");return $e.createHash("sha256").update(e,"utf8").digest("hex")}function xe(e,a){if(!$e)throw Error("Synchronous hmac not available in browser. Use signRequestAsync() instead.");return $e.createHmac("sha256",e).update(a,"utf8").digest()}async function lt(e){let a=new TextEncoder().encode(e),r=await crypto.subtle.digest("SHA-256",a);return Ka(new Uint8Array(r))}async function We(e,a){let r=new TextEncoder,n=typeof e==="string"?r.encode(e):e,i=r.encode(a),o=await crypto.subtle.importKey("raw",n.buffer,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),c=await crypto.subtle.sign("HMAC",o,i.buffer);return new Uint8Array(c)}function Ka(e){return Array.from(e).map((a)=>a.toString(16).padStart(2,"0")).join("")}function qa(e,a,r,n,i,o){let c=`${e}:${a}:${r}:${n}`,u=o.get(c);if(!u){let d=xe(`AWS4${e}`,a),m=xe(d,r),p=xe(m,n);if(u=xe(p,"aws4_request"),o.size>=Qa){let g=o.keys().next().value;if(g)o.delete(g)}o.set(c,u)}return xe(u,i).toString("hex")}async function Ha(e,a,r,n,i,o){let c=`${e}:${a}:${r}:${n}`,u=o.get(c);if(!u){let m=await We(`AWS4${e}`,a),p=await We(m,r),g=await We(p,n);if(u=await We(g,"aws4_request"),o.size>=Qa){let h=o.keys().next().value;if(h)o.delete(h)}o.set(c,u)}let d=await We(u,i);return Ka(d)}function za(e,a){return a.includes(e)}function ut(e,a,r){let n=a*Math.pow(2,e),i=Math.random()*0.3*n;return Math.min(n+i,r)}function dt(e){return new Promise((a)=>setTimeout(a,e))}async function hi(e,a){let{maxRetries:r=3,initialDelayMs:n=100,maxDelayMs:i=5000,retryableStatusCodes:o=[429,500,502,503,504],timeoutMs:c=30000}=a??{},u,d;for(let m=0;m<=r;m++){let p=ae(e),g={method:p.method,headers:p.headers};if(p.body)g.body=p.body;let h=new AbortController,y=setTimeout(()=>h.abort(),c);g.signal=h.signal;try{let f=await fetch(p.url,g);if(clearTimeout(y),d=f,f.ok)return f;if(m<r&&za(f.status,o)){let v=ut(m,n,i);await dt(v);continue}let b=await f.text();throw Error(`AWS API request failed (${f.status}): ${b}`)}catch(f){if(clearTimeout(y),u=f,f instanceof Error&&f.name==="AbortError")u=Error(`Request timed out after ${c}ms`);if(m<r&&!(f instanceof Error&&f.message.includes("AWS API request failed"))){let b=ut(m,n,i);await dt(b);continue}throw u}}throw u??Error("Request failed after retries")}async function vp(e){return hi(e,{maxRetries:0})}async function Tp(e,a){let{maxRetries:r=3,initialDelayMs:n=100,maxDelayMs:i=5000,retryableStatusCodes:o=[429,500,502,503,504],timeoutMs:c=30000}=a??{},u;for(let d=0;d<=r;d++){let m=await yc(e),p={method:m.method,headers:m.headers};if(m.body)p.body=m.body;let g=new AbortController,h=setTimeout(()=>g.abort(),c);p.signal=g.signal;try{let y=await fetch(m.url,p);if(clearTimeout(h),y.ok)return y;if(d<r&&za(y.status,o)){let b=ut(d,n,i);await dt(b);continue}let f=await y.text();throw Error(`AWS API request failed (${y.status}): ${f}`)}catch(y){if(clearTimeout(h),u=y,y instanceof Error&&y.name==="AbortError")u=Error(`Request timed out after ${c}ms`);if(d<r&&!(y instanceof Error&&y.message.includes("AWS API request failed"))){let f=ut(d,n,i);await dt(f);continue}throw u}}throw u??Error("Request failed after retries")}async function Ws(e){let a=await e.text(),r={},n=/<(\w+)>([^<]+)<\/\1>/g,i;while((i=n.exec(a))!==null){let[,o,c]=i;r[o]=c}return r}async function Ep(e){return await e.json()}function Cp(){fe.clear()}function wp(){return fe.size}function Ap(){return $e!==void 0}function Ip(){return typeof crypto<"u"&&typeof crypto.subtle<"u"}var $e,fe,Qa=100,Ja,Ye=Rr(async()=>{try{$e=await import("node:crypto")}catch{}fe=new Map,Ja={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"}}),Rp={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}},Pp={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}}}},Sc=".ts-cloud",bc="TS_CLOUD_STATE_DIR",Gt=null;function Gs(e){Gt=e?.trim()||null}function Ks(){return Boolean(process.env[bc]?.trim()||Gt)}function Ao(){return process.env[bc]?.trim()||Gt||Sc}function et(...e){return mt(Ao(),...e)}function A(e,...a){let r=Ao();return Ot(r)?mt(r,...a):mt(e,r,...a)}function Js(e,a=process.cwd()){let r=(i,o)=>{let c=Mr(i,o);return c===""||!c.startsWith("..")&&!Ot(c)},n=Ot(e)?e:mt(a,e);return r(A(a),n)}function vc(e){let a=e.infrastructure?.compute!=null,r=Object.values(e.environments??{}).some((n)=>n?.app!=null);return{server:a,serverless:r}}function H(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:a}=vc(e);return a?"serverless":"server"}function Pr(e){let{server:a,serverless:r}=vc(e);if(a&&r)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"&&r&&!a)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&a&&!r)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function w(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function Or(e){return typeof e==="object"&&e!==null?e:{}}function Dd(e){return e===!0||typeof e==="object"&&e!==null}function xr(e,a){let r=a?e.environments?.[a]:void 0;if(r?.domain)return r.domain;let n=Object.values(e.sites??{}),i=e.sites?.main?.domain??n.find((o)=>o.domain)?.domain;if(i)return i;return`${e.project?.slug??"app"}.local`}function Br(e){let a=e.indexOf(".");return a>0?e.slice(a+1):void 0}function yi(e,a={}){let r=e.infrastructure?.compute?.managedServices?.mail,n=Or(r),i=a.environmentType??(a.environment?e.environments?.[a.environment]?.type:void 0),o=n.mode??(i==="production"?"server":"catcher"),c=o==="server",u=xr(e,a.environment),d=n.hostname??(c?`mail.${u}`:"localhost"),m=n.ports??{},p=c?{smtp:m.smtp??25,submission:m.submission??587,submissions:m.submissions??465,imap:m.imap??143,imaps:m.imaps??993,webmail:m.webmail??8080,managesieve:m.managesieve}:{smtp:m.smtp??1025,submission:m.submission,submissions:m.submissions,imap:m.imap,imaps:m.imaps,webmail:m.webmail??8025,managesieve:m.managesieve},g=n.tls??{},h=g.enabled??c,y=!!(g.certPath&&g.keyPath),f=(n.accounts??[]).map((M)=>({address:M.address,password:M.password})),b=typeof n.dkim==="object"&&n.dkim!==null?n.dkim:{},v=n.dkim===!1?!1:n.dkim===!0||c,T=typeof n.webmail==="object"&&n.webmail!==null?n.webmail:{},I=n.webmail===!1?!1:T.enabled??!0,C=n.spam??{},N=n.delivery??(c?"direct":"none"),R=n.expose??c,k=Br(d),x=[...new Set([d,...k?[k]:[],...n.domains??[]])];return{enabled:Dd(r),mode:o,version:n.version,hostname:d,domains:x,ports:p,tls:{enabled:h,acme:h&&!y&&(g.acme??!0),certPath:g.certPath,keyPath:g.keyPath,requireForAuth:g.requireForAuth??(h&&c),acmeEmail:g.acmeEmail??f[0]?.address},dkim:{enabled:v,selector:b.selector??"default",rotate:b.rotate??!1,rotateIntervalDays:b.rotateIntervalDays??90},webmail:{enabled:I,port:T.port??p.webmail,domain:T.domain},delivery:N,sesRegion:n.sesRegion??"us-east-1",accounts:f,storagePath:n.storagePath??"/var/lib/mail",maxMessageSize:n.maxMessageSize??26214400,spam:{enabled:C.enabled??c,enforce:C.enforce??!1,junkScore:C.junkScore??5,rejectScore:C.rejectScore??12,dnsbl:C.dnsbl??c,greylist:C.greylist??!1},webhookUrl:n.webhookUrl,expose:R,bindAddress:R?"0.0.0.0":"127.0.0.1"}}function Xs(e){if(!e.enabled||!e.expose)return[];let a=[e.ports.smtp,e.ports.submission,e.ports.submissions,e.ports.imap,e.ports.imaps,e.ports.managesieve].filter((r)=>typeof r==="number");if(e.webmail.enabled&&!e.webmail.domain)a.push(e.webmail.port);return[...new Set(a)].sort((r,n)=>r-n)}function Qs(e){if(!e.enabled)return{};let a=e.ports.submission??e.ports.smtp,r={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(a)};if(e.mode==="server"){r.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let n=e.accounts[0];if(n)r.MAIL_USERNAME=n.address,r.MAIL_PASSWORD=n.password}else r.MAIL_ENCRYPTION="null",r.MAIL_USERNAME="null",r.MAIL_PASSWORD="null";return r}function F(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 Io{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,a){return this.template.Resources[e]=a,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,a){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=a,this}addOutput(e,a){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=a,this}addMetadata(e,a){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[e]=a,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,a=0){let r=" ".repeat(a),n="";for(let[i,o]of Object.entries(e)){if(o===null||o===void 0)continue;if(typeof o==="object"&&!Array.isArray(o))n+=`${r}${i}:
|
|
14
14
|
${this.convertToYAML(o,a+1)}`;else if(Array.isArray(o)){n+=`${r}${i}:
|
|
15
15
|
`;for(let c of o)if(typeof c==="object")n+=`${r} -
|
|
16
16
|
${this.convertToYAML(c,a+2)}`;else n+=`${r} - ${c}
|
|
@@ -20,7 +20,7 @@ ${this.convertToYAML(c,a+2)}`;else n+=`${r} - ${c}
|
|
|
20
20
|
`),a.join(`
|
|
21
21
|
`);if(a.push(`Total changes: ${e.summary.totalChanges}`),a.push(`Requires replacement: ${e.summary.requiresReplacement?"Yes":"No"}
|
|
22
22
|
`),e.summary.dangerousChanges.length>0){a.push("⚠️ DANGEROUS CHANGES DETECTED:");for(let r of e.summary.dangerousChanges)a.push(` • ${r}`);a.push("")}if(e.added.length>0){a.push(`✅ Resources to Add (${e.added.length}):`);for(let r of e.added)a.push(` + ${r.logicalId} (${r.resourceType})`);a.push("")}if(e.removed.length>0){a.push(`❌ Resources to Remove (${e.removed.length}):`);for(let r of e.removed)a.push(` - ${r.logicalId} (${r.resourceType})`);a.push("")}if(e.replaced.length>0){a.push(`\uD83D\uDD04 Resources to Replace (${e.replaced.length}):`);for(let r of e.replaced){if(a.push(` ~ ${r.logicalId} (${r.resourceType})`),r.reason)a.push(` Reason: ${r.reason}`);if(r.changes){for(let n of r.changes.slice(0,3))a.push(` • ${n.path}: ${JSON.stringify(n.oldValue)} → ${JSON.stringify(n.newValue)}`);if(r.changes.length>3)a.push(` ... and ${r.changes.length-3} more changes`)}}a.push("")}if(e.updated.length>0){a.push(`\uD83D\uDCDD Resources to Update (${e.updated.length}):`);for(let r of e.updated)if(a.push(` ~ ${r.logicalId} (${r.resourceType})`),r.changes){for(let n of r.changes.slice(0,3))a.push(` • ${n.path}: ${JSON.stringify(n.oldValue)} → ${JSON.stringify(n.newValue)}`);if(r.changes.length>3)a.push(` ... and ${r.changes.length-3} more changes`)}a.push("")}if(e.unchanged.length>0)a.push(`⚪ Unchanged Resources (${e.unchanged.length})`);return a.join(`
|
|
23
|
-
`)}class Ue{static createBucket(e){let{name:a,bucketName:r,slug:n,environment:i,public:o=!1,versioning:c=!1,website:u=!1,encryption:d=!0,intelligentTiering:m=!1,cors:p,lifecycleRules:g}=e,h=r??l({slug:n,environment:i,resourceType:"s3",suffix:a}),y=s(h),f={Type:"AWS::S3::Bucket",Properties:{BucketName:h}};if(d)f.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(c)f.Properties.VersioningConfiguration={Status:"Enabled"};if(u)f.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!o)f.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(p&&p.length>0)f.Properties.CorsConfiguration={CorsRules:p.map((T)=>({AllowedOrigins:T.allowedOrigins,AllowedMethods:T.allowedMethods,AllowedHeaders:T.allowedHeaders,MaxAge:T.maxAge}))};if(g&&g.length>0)f.Properties.LifecycleConfiguration={Rules:g.map((T)=>({Id:T.id,Status:T.enabled?"Enabled":"Disabled",ExpirationInDays:T.expirationDays,Transitions:T.transitions?.map((w)=>({TransitionInDays:w.days,StorageClass:w.storageClass}))}))};if(m&&g){let T={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!f.Properties.LifecycleConfiguration)f.Properties.LifecycleConfiguration={Rules:[]};f.Properties.LifecycleConfiguration.Rules.push({Id:T.id,Status:"Enabled",Transitions:T.transitions?.map((w)=>({TransitionInDays:w.days,StorageClass:w.storageClass}))})}let b;if(o)b={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:P.Ref(y),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[P.Join("",[P.GetAtt(y,"Arn"),"/*"])]}]}}};return{bucket:f,bucketPolicy:b,logicalId:y}}static enableVersioning(e){if(!e.Properties)e.Properties={};return e.Properties.VersioningConfiguration={Status:"Enabled"},e}static enableWebsiteHosting(e,a="index.html",r="error.html"){if(!e.Properties)e.Properties={};return e.Properties.WebsiteConfiguration={IndexDocument:a,ErrorDocument:r},e}static setLifecycleRules(e,a){if(!e.Properties)e.Properties={};return e.Properties.LifecycleConfiguration={Rules:a.map((r)=>({Id:r.id,Status:r.enabled?"Enabled":"Disabled",ExpirationInDays:r.expirationDays,Transitions:r.transitions?.map((n)=>({TransitionInDays:n.days,StorageClass:n.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,a){if(!e.Properties)e.Properties={};if(!e.Properties.NotificationConfiguration)e.Properties.NotificationConfiguration={};if(!e.Properties.NotificationConfiguration.LambdaConfigurations)e.Properties.NotificationConfiguration.LambdaConfigurations=[];let r={Event:a.events[0],Function:a.functionArn};if(a.filter)r.Filter={S3Key:{Rules:[...a.filter.prefix?[{Name:"prefix",Value:a.filter.prefix}]:[],...a.filter.suffix?[{Name:"suffix",Value:a.filter.suffix}]:[]]}};for(let n of a.events){let i={...r,Event:n};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,a)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:a,suffix:".jpg"}}),onFileType:(e,a,r)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:r,suffix:a}}),onFolderUpload:(e,a)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:a.endsWith("/")?a:`${a}/`}})};static createBackupPlan(e){let{name:a,slug:r,environment:n,bucketLogicalIds:i,retentionDays:o,schedule:c="cron(0 5 * * ? *)",vaultName:u,enableContinuousBackup:d=!1,moveToColdStorageAfterDays:m}=e,p=u||l({slug:r,environment:n,resourceType:"backup-vault",suffix:a}),g=s(p),h={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:p}},y=l({slug:r,environment:n,resourceType:"backup-role",suffix:a}),f=s(y),b={Type:"AWS::IAM::Role",Properties:{RoleName:y,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"]}},T=l({slug:r,environment:n,resourceType:"backup-plan",suffix:a}),w=s(T),I={DeleteAfterDays:o};if(m&&m<o)I.MoveToColdStorageAfterDays=m;let v={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:T,BackupPlanRule:[{RuleName:`${a}-daily-backup`,TargetBackupVault:P.Ref(g),ScheduleExpression:c,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:I,EnableContinuousBackup:d}]}}},N=l({slug:r,environment:n,resourceType:"backup-selection",suffix:a}),R=s(N),k=i.map((M)=>P.GetAtt(M,"Arn")),x={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:P.Ref(w),BackupSelection:{SelectionName:N,IamRoleArn:P.GetAtt(f,"Arn"),Resources:k}}};return{vault:h,plan:v,selection:x,role:b,vaultLogicalId:g,planLogicalId:w,selectionLogicalId:R,roleLogicalId:f}}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:a,environment:r,sourceDomain:n,targetDomain:i,protocol:o="https"}=e,c=l({slug:a,environment:r,resourceType:"s3",suffix:"www-redirect"}),u=s(c),d={Type:"AWS::S3::Bucket",Properties:{BucketName:n,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:i,Protocol:o}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},m={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:P.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[P.Join("",[P.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:d,bucketPolicy:m,logicalId:u}}static createDocsBucket(e){let{slug:a,environment:r,domain:n}=e,i=n||l({slug:a,environment:r,resourceType:"s3",suffix:"docs"}),o=s(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:o}}static createEmailBucket(e){let{slug:a,environment:r}=e,n=l({slug:a,environment:r,resourceType:"s3",suffix:"email"}),i=s(n),o={Type:"AWS::S3::Bucket",Properties:{BucketName:n,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"}]}]}}},c={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:P.Ref(i),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:P.Join("",[P.GetAtt(i,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":P.Ref("AWS::AccountId")}}}]}}};return{bucket:o,bucketPolicy:c,logicalId:i}}static docsExist(e={}){let{projectRoot:a=process.cwd(),docsPaths:r=["docs","documentation","doc"]}=e;for(let n of r){let i=le(a,n);if(Ge(i)){let o=["dist","build",".bunpress/dist","_site","out","public"];for(let c of o){let u=le(i,c);if(Ge(u))try{if(Qr(u).length>0)return{exists:!0,path:i,hasDistFolder:!0,distPath:u}}catch{}}return{exists:!0,path:i,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(e){let a=Ue.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!a.exists)return{bucket:null,logicalId:null,docsInfo:a};let r=Ue.createDocsBucket({slug:e.slug,environment:e.environment,domain:e.domain});return{bucket:r.bucket,bucketPolicy:r.bucketPolicy,logicalId:r.logicalId,docsInfo:a}}static createPrivateBucket(e){let{slug:a,environment:r,enableVersioning:n=!0,retentionDays:i,encryptionKeyArn:o}=e,c=l({slug:a,environment:r,resourceType:"s3",suffix:"private"}),u=s(c);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:c,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:o?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:o}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:n?{Status:"Enabled"}:void 0,LifecycleConfiguration:i?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:i}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:u}}static checkSourcePaths(e={}){let{projectRoot:a=process.cwd(),paths:r={}}=e,n=r.web||"views/web/dist",i=r.docs||"docs/dist",o=r.private||"private";return{web:{exists:Ge(le(a,n)),path:le(a,n)},docs:{exists:Ge(le(a,i)),path:le(a,i)},private:{exists:Ge(le(a,o)),path:le(a,o)}}}static createDeploymentBuckets(e){let{slug:a,environment:r,domain:n,projectRoot:i,paths:o}=e,c=Ue.checkSourcePaths({projectRoot:i,paths:o}),u={},d={web:!1,docs:!1,private:!1},m=Ue.createBucket({name:"web",slug:a,environment:r,public:!1,versioning:!1,encryption:!0});if(u[m.logicalId]=m.bucket,d.web=!0,c.docs.exists){let p=Ue.createDocsBucket({slug:a,environment:r,domain:n?`docs.${n}`:void 0});if(u[p.logicalId]=p.bucket,p.bucketPolicy)u[`${p.logicalId}Policy`]=p.bucketPolicy;d.docs=!0}if(c.private.exists){let p=Ue.createPrivateBucket({slug:a,environment:r,enableVersioning:!0});u[p.logicalId]=p.bucket,d.private=!0}return{resources:u,created:d,sourcePaths:c}}}class Et{static createRepository(e){let{name:a,slug:r,environment:n,scanOnPush:i=!0,imageMutability:o="MUTABLE",encryption:c="AES256",kmsKey:u,lifecyclePolicy:d,tags:m}=e,p=l({slug:r,environment:n,resourceType:"ecr",suffix:a}),g=s(p),h={Type:"AWS::ECR::Repository",Properties:{RepositoryName:p,ImageTagMutability:o,ImageScanningConfiguration:{ScanOnPush:i},EncryptionConfiguration:{EncryptionType:c,...u&&c==="KMS"?{KmsKey:u}:{}}}};if(d)h.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Et.generateLifecyclePolicy(d))};if(m)h.Properties.Tags=Object.entries(m).map(([y,f])=>({Key:y,Value:f}));return{repository:h,logicalId:g}}static generateLifecyclePolicy(e){let a=[];if(e.untaggedImageExpireDays!==void 0)a.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)a.push({rulePriority:a.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount},action:{type:"expire"}});if(e.maxImageAgeDays!==void 0)a.push({rulePriority:a.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:a}}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,a){if(!e.Properties)e.Properties={};return e.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Et.generateLifecyclePolicy(a))},e}static addCrossAccountAccess(e,a){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:a.map((r)=>`arn:aws:iam::${r}: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:a="oven/bun:1-debian",serverPath:r,port:n=3000,additionalDirs:i=[],healthCheckEndpoint:o="/health",nodeCompatible:c=!1,envVars:u={},buildCommands:d=[],runCommand:m}=e,p=["app","config",...i],g=m||`bun run ${r}`,h=`# Multi-stage build for Bun application
|
|
23
|
+
`)}class Ue{static createBucket(e){let{name:a,bucketName:r,slug:n,environment:i,public:o=!1,versioning:c=!1,website:u=!1,encryption:d=!0,intelligentTiering:m=!1,cors:p,lifecycleRules:g}=e,h=r??l({slug:n,environment:i,resourceType:"s3",suffix:a}),y=s(h),f={Type:"AWS::S3::Bucket",Properties:{BucketName:h}};if(d)f.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(c)f.Properties.VersioningConfiguration={Status:"Enabled"};if(u)f.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!o)f.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(p&&p.length>0)f.Properties.CorsConfiguration={CorsRules:p.map((v)=>({AllowedOrigins:v.allowedOrigins,AllowedMethods:v.allowedMethods,AllowedHeaders:v.allowedHeaders,MaxAge:v.maxAge}))};if(g&&g.length>0)f.Properties.LifecycleConfiguration={Rules:g.map((v)=>({Id:v.id,Status:v.enabled?"Enabled":"Disabled",ExpirationInDays:v.expirationDays,Transitions:v.transitions?.map((T)=>({TransitionInDays:T.days,StorageClass:T.storageClass}))}))};if(m&&g){let v={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!f.Properties.LifecycleConfiguration)f.Properties.LifecycleConfiguration={Rules:[]};f.Properties.LifecycleConfiguration.Rules.push({Id:v.id,Status:"Enabled",Transitions:v.transitions?.map((T)=>({TransitionInDays:T.days,StorageClass:T.storageClass}))})}let b;if(o)b={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:P.Ref(y),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[P.Join("",[P.GetAtt(y,"Arn"),"/*"])]}]}}};return{bucket:f,bucketPolicy:b,logicalId:y}}static enableVersioning(e){if(!e.Properties)e.Properties={};return e.Properties.VersioningConfiguration={Status:"Enabled"},e}static enableWebsiteHosting(e,a="index.html",r="error.html"){if(!e.Properties)e.Properties={};return e.Properties.WebsiteConfiguration={IndexDocument:a,ErrorDocument:r},e}static setLifecycleRules(e,a){if(!e.Properties)e.Properties={};return e.Properties.LifecycleConfiguration={Rules:a.map((r)=>({Id:r.id,Status:r.enabled?"Enabled":"Disabled",ExpirationInDays:r.expirationDays,Transitions:r.transitions?.map((n)=>({TransitionInDays:n.days,StorageClass:n.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,a){if(!e.Properties)e.Properties={};if(!e.Properties.NotificationConfiguration)e.Properties.NotificationConfiguration={};if(!e.Properties.NotificationConfiguration.LambdaConfigurations)e.Properties.NotificationConfiguration.LambdaConfigurations=[];let r={Event:a.events[0],Function:a.functionArn};if(a.filter)r.Filter={S3Key:{Rules:[...a.filter.prefix?[{Name:"prefix",Value:a.filter.prefix}]:[],...a.filter.suffix?[{Name:"suffix",Value:a.filter.suffix}]:[]]}};for(let n of a.events){let i={...r,Event:n};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,a)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:a,suffix:".jpg"}}),onFileType:(e,a,r)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:r,suffix:a}}),onFolderUpload:(e,a)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:a.endsWith("/")?a:`${a}/`}})};static createBackupPlan(e){let{name:a,slug:r,environment:n,bucketLogicalIds:i,retentionDays:o,schedule:c="cron(0 5 * * ? *)",vaultName:u,enableContinuousBackup:d=!1,moveToColdStorageAfterDays:m}=e,p=u||l({slug:r,environment:n,resourceType:"backup-vault",suffix:a}),g=s(p),h={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:p}},y=l({slug:r,environment:n,resourceType:"backup-role",suffix:a}),f=s(y),b={Type:"AWS::IAM::Role",Properties:{RoleName:y,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"]}},v=l({slug:r,environment:n,resourceType:"backup-plan",suffix:a}),T=s(v),I={DeleteAfterDays:o};if(m&&m<o)I.MoveToColdStorageAfterDays=m;let C={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:v,BackupPlanRule:[{RuleName:`${a}-daily-backup`,TargetBackupVault:P.Ref(g),ScheduleExpression:c,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:I,EnableContinuousBackup:d}]}}},N=l({slug:r,environment:n,resourceType:"backup-selection",suffix:a}),R=s(N),k=i.map((M)=>P.GetAtt(M,"Arn")),x={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:P.Ref(T),BackupSelection:{SelectionName:N,IamRoleArn:P.GetAtt(f,"Arn"),Resources:k}}};return{vault:h,plan:C,selection:x,role:b,vaultLogicalId:g,planLogicalId:T,selectionLogicalId:R,roleLogicalId:f}}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:a,environment:r,sourceDomain:n,targetDomain:i,protocol:o="https"}=e,c=l({slug:a,environment:r,resourceType:"s3",suffix:"www-redirect"}),u=s(c),d={Type:"AWS::S3::Bucket",Properties:{BucketName:n,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:i,Protocol:o}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},m={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:P.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[P.Join("",[P.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:d,bucketPolicy:m,logicalId:u}}static createDocsBucket(e){let{slug:a,environment:r,domain:n}=e,i=n||l({slug:a,environment:r,resourceType:"s3",suffix:"docs"}),o=s(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:o}}static createEmailBucket(e){let{slug:a,environment:r}=e,n=l({slug:a,environment:r,resourceType:"s3",suffix:"email"}),i=s(n),o={Type:"AWS::S3::Bucket",Properties:{BucketName:n,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"}]}]}}},c={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:P.Ref(i),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:P.Join("",[P.GetAtt(i,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":P.Ref("AWS::AccountId")}}}]}}};return{bucket:o,bucketPolicy:c,logicalId:i}}static docsExist(e={}){let{projectRoot:a=process.cwd(),docsPaths:r=["docs","documentation","doc"]}=e;for(let n of r){let i=le(a,n);if(Ge(i)){let o=["dist","build",".bunpress/dist","_site","out","public"];for(let c of o){let u=le(i,c);if(Ge(u))try{if(Qr(u).length>0)return{exists:!0,path:i,hasDistFolder:!0,distPath:u}}catch{}}return{exists:!0,path:i,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(e){let a=Ue.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!a.exists)return{bucket:null,logicalId:null,docsInfo:a};let r=Ue.createDocsBucket({slug:e.slug,environment:e.environment,domain:e.domain});return{bucket:r.bucket,bucketPolicy:r.bucketPolicy,logicalId:r.logicalId,docsInfo:a}}static createPrivateBucket(e){let{slug:a,environment:r,enableVersioning:n=!0,retentionDays:i,encryptionKeyArn:o}=e,c=l({slug:a,environment:r,resourceType:"s3",suffix:"private"}),u=s(c);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:c,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:o?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:o}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:n?{Status:"Enabled"}:void 0,LifecycleConfiguration:i?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:i}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:u}}static checkSourcePaths(e={}){let{projectRoot:a=process.cwd(),paths:r={}}=e,n=r.web||"views/web/dist",i=r.docs||"docs/dist",o=r.private||"private";return{web:{exists:Ge(le(a,n)),path:le(a,n)},docs:{exists:Ge(le(a,i)),path:le(a,i)},private:{exists:Ge(le(a,o)),path:le(a,o)}}}static createDeploymentBuckets(e){let{slug:a,environment:r,domain:n,projectRoot:i,paths:o}=e,c=Ue.checkSourcePaths({projectRoot:i,paths:o}),u={},d={web:!1,docs:!1,private:!1},m=Ue.createBucket({name:"web",slug:a,environment:r,public:!1,versioning:!1,encryption:!0});if(u[m.logicalId]=m.bucket,d.web=!0,c.docs.exists){let p=Ue.createDocsBucket({slug:a,environment:r,domain:n?`docs.${n}`:void 0});if(u[p.logicalId]=p.bucket,p.bucketPolicy)u[`${p.logicalId}Policy`]=p.bucketPolicy;d.docs=!0}if(c.private.exists){let p=Ue.createPrivateBucket({slug:a,environment:r,enableVersioning:!0});u[p.logicalId]=p.bucket,d.private=!0}return{resources:u,created:d,sourcePaths:c}}}class Et{static createRepository(e){let{name:a,slug:r,environment:n,scanOnPush:i=!0,imageMutability:o="MUTABLE",encryption:c="AES256",kmsKey:u,lifecyclePolicy:d,tags:m}=e,p=l({slug:r,environment:n,resourceType:"ecr",suffix:a}),g=s(p),h={Type:"AWS::ECR::Repository",Properties:{RepositoryName:p,ImageTagMutability:o,ImageScanningConfiguration:{ScanOnPush:i},EncryptionConfiguration:{EncryptionType:c,...u&&c==="KMS"?{KmsKey:u}:{}}}};if(d)h.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Et.generateLifecyclePolicy(d))};if(m)h.Properties.Tags=Object.entries(m).map(([y,f])=>({Key:y,Value:f}));return{repository:h,logicalId:g}}static generateLifecyclePolicy(e){let a=[];if(e.untaggedImageExpireDays!==void 0)a.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)a.push({rulePriority:a.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount},action:{type:"expire"}});if(e.maxImageAgeDays!==void 0)a.push({rulePriority:a.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:a}}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,a){if(!e.Properties)e.Properties={};return e.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Et.generateLifecyclePolicy(a))},e}static addCrossAccountAccess(e,a){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:a.map((r)=>`arn:aws:iam::${r}: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:a="oven/bun:1-debian",serverPath:r,port:n=3000,additionalDirs:i=[],healthCheckEndpoint:o="/health",nodeCompatible:c=!1,envVars:u={},buildCommands:d=[],runCommand:m}=e,p=["app","config",...i],g=m||`bun run ${r}`,h=`# Multi-stage build for Bun application
|
|
24
24
|
# Generated by ts-cloud
|
|
25
25
|
|
|
26
26
|
# Builder stage
|
|
@@ -103,7 +103,7 @@ echo "Image: $IMAGE_URI:${n}"
|
|
|
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(a,null,2).replace(/"/g,"").replace(/,\n/g,`
|
|
106
|
-
`)}`}};static DockerfileTemplates={bunServer:(e,a=3000)=>Et.generateBunDockerfile({serverPath:e,port:a}),bunWithBuild:(e,a,r=3000)=>Et.generateBunDockerfile({serverPath:e,port:r,buildCommands:[a]}),bunFullStack:(e,a=3000)=>Et.generateBunDockerfile({serverPath:e,port:a,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,a=3000)=>Et.generateBunDockerfile({serverPath:e,port:a,healthCheckEndpoint:"/api/health"})}}var ra=[400,403,404,416,429,500,502,503,504],Tc=[500,502,503,504],Ec=["GET","HEAD","OPTIONS"],Bp="-failover-group",wc=["default","media-quality-based"],Cc={min:1,max:3},Ac={min:1,max:10};function na(e){if(e===void 0)return[...Tc];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${ra.join(", ")}). Omit it to use the default ${Tc.join(", ")}.`);let a=e.filter((r)=>!ra.includes(r));if(a.length>0)throw Error(`CloudFront origin failover: ${a.join(", ")} ${a.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${ra.join(", ")}.`);return[...new Set(e)].sort((r,n)=>r-n)}function Ic(e){let{primaryOriginId:a,secondaryOriginId:r}=e;if(!a||!r)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(a===r)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${a}")`);let n=na(e.statusCodes);return Xa(e.selectionCriteria),{Id:e.groupId??`${a}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:n.length,Items:n}},Members:{Quantity:2,Items:[{OriginId:a},{OriginId:r}]},...e.selectionCriteria?{SelectionCriteria:e.selectionCriteria}:{}}}function Xa(e,a="the origin group"){if(e===void 0)return;if(!wc.includes(e))throw Error(`CloudFront origin failover: ${a} has selection criteria ${JSON.stringify(e)}. Allowed: ${wc.join(", ")}.`)}function pt(e,a,r){if(typeof e!=="number"||!Number.isInteger(e)||e<a.min||e>a.max)throw Error(`CloudFront origin: ${r} must be a whole number from ${a.min} to ${a.max}, got ${JSON.stringify(e)}.`)}function jt(e,a="the origin"){let r={};if(e?.connectionAttempts!==void 0)pt(e.connectionAttempts,Cc,`${a} connectionAttempts`),r.ConnectionAttempts=e.connectionAttempts;if(e?.connectionTimeout!==void 0)pt(e.connectionTimeout,Ac,`${a} connectionTimeout (seconds)`),r.ConnectionTimeout=e.connectionTimeout;return r}function Po(e){return{Quantity:1,Items:[Ic(e)]}}function Si(e,a="the cache behavior"){let r=(Array.isArray(e)?e:e?.Items??[]).filter((n)=>!Ec.includes(n.toUpperCase()));if(r.length>0)throw Error(`CloudFront origin failover: ${a} allows ${r.join(", ")}, but a cache behavior that targets an origin group may only allow ${Ec.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function No(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}function Ve(e){if(!e)return[];if(Array.isArray(e))return e;return e.Items??[]}function ie(e){return typeof e==="string"?e:void 0}var Jr=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function bi(e,a="the distribution"){let r=Ve(e.Origins),n=new Set(r.map((p)=>ie(p.Id)).filter((p)=>!!p)),i=new Map(r.map((p)=>[ie(p.Id)??"",p.DomainName])),o=r.some((p)=>ie(p.Id)===void 0);for(let p of r){let g=ie(p.Id)??"(unnamed origin)";if(p.ConnectionAttempts!==void 0)pt(p.ConnectionAttempts,Cc,`${a} origin "${g}" ConnectionAttempts`);if(p.ConnectionTimeout!==void 0)pt(p.ConnectionTimeout,Ac,`${a} origin "${g}" ConnectionTimeout (seconds)`)}let c=e.OriginGroups,u=Ve(c);if(c&&!Array.isArray(c)&&c.Quantity!==void 0&&c.Quantity!==u.length)throw Error(`CloudFront origin failover: ${a} OriginGroups.Quantity is ${c.Quantity} but it lists ${u.length} group(s).`);let d=new Set;for(let p of u){let g=ie(p.Id);if(p.Id===void 0||p.Id==="")throw Error(`CloudFront origin failover: ${a} has an origin group without an Id.`);let h=`${a} origin group "${g??"(intrinsic id)"}"`;if(g){if(d.has(g))throw Error(`CloudFront origin failover: ${a} declares origin group "${g}" twice.`);if(n.has(g))throw Error(`CloudFront origin failover: ${h} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);d.add(g)}let y=p.Members,f=Ve(y);if(f.length!==2||y?.Quantity!==void 0&&y.Quantity!==f.length)throw Error(`CloudFront origin failover: ${h} must have exactly 2 members (a primary and a secondary), it has ${f.length}${y?.Quantity!==void 0&&y.Quantity!==f.length?` with Quantity ${y.Quantity}`:""}.`);let b=f.map((I)=>ie(I.OriginId));for(let I of b)if(I&&!n.has(I)&&!o)throw Error(`CloudFront origin failover: ${h} lists member "${I}", which is not an origin of this distribution. Origins: ${[...n].join(", ")||"(none)"}.`);if(b[0]&&b[0]===b[1])throw Error(`CloudFront origin failover: ${h} lists "${b[0]}" as both primary and secondary.`);let T=p.FailoverCriteria?.StatusCodes,w=Ve(T);if(na(w),T?.Quantity!==void 0&&T.Quantity!==w.length)throw Error(`CloudFront origin failover: ${h} FailoverCriteria.StatusCodes.Quantity is ${T.Quantity} but it lists ${w.length} code(s).`);if(Xa(p.SelectionCriteria,h),p.SelectionCriteria==="media-quality-based")for(let I of b){let v=I?ie(i.get(I)):void 0;if(v&&!Jr.test(v))throw Error(`CloudFront origin failover: ${h} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${I}" is ${v}. Use 'default'.`)}}let m=[];if(e.DefaultCacheBehavior)m.push({behavior:e.DefaultCacheBehavior,name:"the default cache behavior"});for(let p of Ve(e.CacheBehaviors))m.push({behavior:p,name:`the cache behavior for ${JSON.stringify(p.PathPattern)}`});for(let{behavior:p,name:g}of m){let h=ie(p.TargetOriginId);if(!h)continue;if(d.has(h))Si(p.AllowedMethods??["GET","HEAD"],`${g} of ${a} (origin group "${h}")`);else if(!n.has(h)&&!o&&u.every((y)=>ie(y.Id)!==void 0))throw Error(`CloudFront: ${g} of ${a} targets "${h}", which is neither an origin nor an origin group of this distribution.`)}}class Be{static createDistribution(e){let{slug:a,environment:r,origin:n,customDomain:i,certificateArn:o,errorPages:c,cachePolicy:u,edgeFunctions:d,http3:m=!1,comment:p,failoverOrigin:g}=e,h=l({slug:a,environment:r,resourceType:"cdn"}),y=s(h),f={Id:"DefaultOrigin",DomainName:n.domainName,OriginPath:n.originPath||"",...jt(n,"the CDN origin")},b;if(n.type==="s3"){let w=`${y}OAC`;b={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${h}-oac`,Description:`Origin Access Control for ${h}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},f.OriginAccessControlId=P.Ref(w)}else if(n.type==="alb"||n.type==="custom")f.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let T={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:p||`CDN for ${h}`,DefaultRootObject:"index.html",Origins:[f],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:m?"http2and3":"http2"}}};if(i&&o)T.Properties.DistributionConfig.Aliases=[i],T.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:o,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(c&&c.length>0)T.Properties.DistributionConfig.CustomErrorResponses=c.map((w)=>({ErrorCode:w.errorCode,ResponseCode:w.responseCode,ResponsePagePath:w.responsePagePath}));if(d&&d.length>0)T.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=d.map((w)=>({EventType:w.event,LambdaFunctionARN:w.functionArn}));if(g)Be.addOriginFailover(T,g);return{distribution:T,originAccessControl:b,logicalId:y}}static addOriginFailover(e,a){let r=e.Properties.DistributionConfig,n=r.DefaultCacheBehavior,i=n.TargetOriginId,o=a.id??"FailoverOrigin";if(r.OriginGroups&&r.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(Si(n.AllowedMethods??["GET","HEAD"],"the default cache behavior"),r.Origins.some((p)=>p.Id===o))throw Error(`CloudFront origin failover: an origin with id "${o}" already exists`);let c=Ic({primaryOriginId:i,secondaryOriginId:o,statusCodes:a.statusCodes,selectionCriteria:a.selectionCriteria}),u=a.type??(No(a.domainName)?"s3":"custom"),d={Id:o,DomainName:a.domainName,OriginPath:a.originPath||"",...jt(a,"the failover origin")},m=jt(a.primary,"the primary origin");if(Object.keys(m).length>0){let p=r.Origins.find((g)=>g.Id===i);if(p)Object.assign(p,m)}if(u==="s3"){let p=r.Origins.find((g)=>g.Id===i);if(d.S3OriginConfig={OriginAccessIdentity:""},p?.OriginAccessControlId)d.OriginAccessControlId=p.OriginAccessControlId}else d.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return r.Origins.push(d),r.OriginGroups={Quantity:1,Items:[c]},n.TargetOriginId=c.Id,bi(r),e}static setCustomDomain(e,a,r){return e.Properties.DistributionConfig.Aliases=[a],e.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:r,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},e}static setErrorPages(e,a){return e.Properties.DistributionConfig.CustomErrorResponses=a.map((r)=>({ErrorCode:r.errorCode,ResponseCode:r.responseCode,ResponsePagePath:r.responsePagePath})),e}static enableHttp3(e){return e.Properties.DistributionConfig.HttpVersion="http2and3",e}static addEdgeFunction(e,a,r){if(!e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:a,LambdaFunctionARN:r}),e}static setCachePolicy(e,a){return e.Properties.DistributionConfig.Comment=`${e.Properties.DistributionConfig.Comment||""} (TTL: ${a.default||86400}s)`,e}static createSpaDistribution(e){return Be.createDistribution({...e,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(e){let{slug:a,environment:r}=e,n=l({slug:a,environment:r,resourceType:"edge-docs"}),i=s(n),o=s(`${n}-role`),c=s(`${n}-version`),u={Type:"AWS::IAM::Role",Properties:{RoleName:`${n}-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"]}},d=`
|
|
106
|
+
`)}`}};static DockerfileTemplates={bunServer:(e,a=3000)=>Et.generateBunDockerfile({serverPath:e,port:a}),bunWithBuild:(e,a,r=3000)=>Et.generateBunDockerfile({serverPath:e,port:r,buildCommands:[a]}),bunFullStack:(e,a=3000)=>Et.generateBunDockerfile({serverPath:e,port:a,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,a=3000)=>Et.generateBunDockerfile({serverPath:e,port:a,healthCheckEndpoint:"/api/health"})}}var ra=[400,403,404,416,429,500,502,503,504],Tc=[500,502,503,504],Ec=["GET","HEAD","OPTIONS"],Bp="-failover-group",Cc=["default","media-quality-based"],wc={min:1,max:3},Ac={min:1,max:10};function na(e){if(e===void 0)return[...Tc];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${ra.join(", ")}). Omit it to use the default ${Tc.join(", ")}.`);let a=e.filter((r)=>!ra.includes(r));if(a.length>0)throw Error(`CloudFront origin failover: ${a.join(", ")} ${a.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${ra.join(", ")}.`);return[...new Set(e)].sort((r,n)=>r-n)}function Ic(e){let{primaryOriginId:a,secondaryOriginId:r}=e;if(!a||!r)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(a===r)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${a}")`);let n=na(e.statusCodes);return Xa(e.selectionCriteria),{Id:e.groupId??`${a}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:n.length,Items:n}},Members:{Quantity:2,Items:[{OriginId:a},{OriginId:r}]},...e.selectionCriteria?{SelectionCriteria:e.selectionCriteria}:{}}}function Xa(e,a="the origin group"){if(e===void 0)return;if(!Cc.includes(e))throw Error(`CloudFront origin failover: ${a} has selection criteria ${JSON.stringify(e)}. Allowed: ${Cc.join(", ")}.`)}function pt(e,a,r){if(typeof e!=="number"||!Number.isInteger(e)||e<a.min||e>a.max)throw Error(`CloudFront origin: ${r} must be a whole number from ${a.min} to ${a.max}, got ${JSON.stringify(e)}.`)}function jt(e,a="the origin"){let r={};if(e?.connectionAttempts!==void 0)pt(e.connectionAttempts,wc,`${a} connectionAttempts`),r.ConnectionAttempts=e.connectionAttempts;if(e?.connectionTimeout!==void 0)pt(e.connectionTimeout,Ac,`${a} connectionTimeout (seconds)`),r.ConnectionTimeout=e.connectionTimeout;return r}function Po(e){return{Quantity:1,Items:[Ic(e)]}}function Si(e,a="the cache behavior"){let r=(Array.isArray(e)?e:e?.Items??[]).filter((n)=>!Ec.includes(n.toUpperCase()));if(r.length>0)throw Error(`CloudFront origin failover: ${a} allows ${r.join(", ")}, but a cache behavior that targets an origin group may only allow ${Ec.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function No(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}function Ve(e){if(!e)return[];if(Array.isArray(e))return e;return e.Items??[]}function ie(e){return typeof e==="string"?e:void 0}var Jr=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function bi(e,a="the distribution"){let r=Ve(e.Origins),n=new Set(r.map((p)=>ie(p.Id)).filter((p)=>!!p)),i=new Map(r.map((p)=>[ie(p.Id)??"",p.DomainName])),o=r.some((p)=>ie(p.Id)===void 0);for(let p of r){let g=ie(p.Id)??"(unnamed origin)";if(p.ConnectionAttempts!==void 0)pt(p.ConnectionAttempts,wc,`${a} origin "${g}" ConnectionAttempts`);if(p.ConnectionTimeout!==void 0)pt(p.ConnectionTimeout,Ac,`${a} origin "${g}" ConnectionTimeout (seconds)`)}let c=e.OriginGroups,u=Ve(c);if(c&&!Array.isArray(c)&&c.Quantity!==void 0&&c.Quantity!==u.length)throw Error(`CloudFront origin failover: ${a} OriginGroups.Quantity is ${c.Quantity} but it lists ${u.length} group(s).`);let d=new Set;for(let p of u){let g=ie(p.Id);if(p.Id===void 0||p.Id==="")throw Error(`CloudFront origin failover: ${a} has an origin group without an Id.`);let h=`${a} origin group "${g??"(intrinsic id)"}"`;if(g){if(d.has(g))throw Error(`CloudFront origin failover: ${a} declares origin group "${g}" twice.`);if(n.has(g))throw Error(`CloudFront origin failover: ${h} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);d.add(g)}let y=p.Members,f=Ve(y);if(f.length!==2||y?.Quantity!==void 0&&y.Quantity!==f.length)throw Error(`CloudFront origin failover: ${h} must have exactly 2 members (a primary and a secondary), it has ${f.length}${y?.Quantity!==void 0&&y.Quantity!==f.length?` with Quantity ${y.Quantity}`:""}.`);let b=f.map((I)=>ie(I.OriginId));for(let I of b)if(I&&!n.has(I)&&!o)throw Error(`CloudFront origin failover: ${h} lists member "${I}", which is not an origin of this distribution. Origins: ${[...n].join(", ")||"(none)"}.`);if(b[0]&&b[0]===b[1])throw Error(`CloudFront origin failover: ${h} lists "${b[0]}" as both primary and secondary.`);let v=p.FailoverCriteria?.StatusCodes,T=Ve(v);if(na(T),v?.Quantity!==void 0&&v.Quantity!==T.length)throw Error(`CloudFront origin failover: ${h} FailoverCriteria.StatusCodes.Quantity is ${v.Quantity} but it lists ${T.length} code(s).`);if(Xa(p.SelectionCriteria,h),p.SelectionCriteria==="media-quality-based")for(let I of b){let C=I?ie(i.get(I)):void 0;if(C&&!Jr.test(C))throw Error(`CloudFront origin failover: ${h} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${I}" is ${C}. Use 'default'.`)}}let m=[];if(e.DefaultCacheBehavior)m.push({behavior:e.DefaultCacheBehavior,name:"the default cache behavior"});for(let p of Ve(e.CacheBehaviors))m.push({behavior:p,name:`the cache behavior for ${JSON.stringify(p.PathPattern)}`});for(let{behavior:p,name:g}of m){let h=ie(p.TargetOriginId);if(!h)continue;if(d.has(h))Si(p.AllowedMethods??["GET","HEAD"],`${g} of ${a} (origin group "${h}")`);else if(!n.has(h)&&!o&&u.every((y)=>ie(y.Id)!==void 0))throw Error(`CloudFront: ${g} of ${a} targets "${h}", which is neither an origin nor an origin group of this distribution.`)}}class Be{static createDistribution(e){let{slug:a,environment:r,origin:n,customDomain:i,certificateArn:o,errorPages:c,cachePolicy:u,edgeFunctions:d,http3:m=!1,comment:p,failoverOrigin:g}=e,h=l({slug:a,environment:r,resourceType:"cdn"}),y=s(h),f={Id:"DefaultOrigin",DomainName:n.domainName,OriginPath:n.originPath||"",...jt(n,"the CDN origin")},b;if(n.type==="s3"){let T=`${y}OAC`;b={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${h}-oac`,Description:`Origin Access Control for ${h}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},f.OriginAccessControlId=P.Ref(T)}else if(n.type==="alb"||n.type==="custom")f.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let v={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:p||`CDN for ${h}`,DefaultRootObject:"index.html",Origins:[f],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:m?"http2and3":"http2"}}};if(i&&o)v.Properties.DistributionConfig.Aliases=[i],v.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:o,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(c&&c.length>0)v.Properties.DistributionConfig.CustomErrorResponses=c.map((T)=>({ErrorCode:T.errorCode,ResponseCode:T.responseCode,ResponsePagePath:T.responsePagePath}));if(d&&d.length>0)v.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=d.map((T)=>({EventType:T.event,LambdaFunctionARN:T.functionArn}));if(g)Be.addOriginFailover(v,g);return{distribution:v,originAccessControl:b,logicalId:y}}static addOriginFailover(e,a){let r=e.Properties.DistributionConfig,n=r.DefaultCacheBehavior,i=n.TargetOriginId,o=a.id??"FailoverOrigin";if(r.OriginGroups&&r.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(Si(n.AllowedMethods??["GET","HEAD"],"the default cache behavior"),r.Origins.some((p)=>p.Id===o))throw Error(`CloudFront origin failover: an origin with id "${o}" already exists`);let c=Ic({primaryOriginId:i,secondaryOriginId:o,statusCodes:a.statusCodes,selectionCriteria:a.selectionCriteria}),u=a.type??(No(a.domainName)?"s3":"custom"),d={Id:o,DomainName:a.domainName,OriginPath:a.originPath||"",...jt(a,"the failover origin")},m=jt(a.primary,"the primary origin");if(Object.keys(m).length>0){let p=r.Origins.find((g)=>g.Id===i);if(p)Object.assign(p,m)}if(u==="s3"){let p=r.Origins.find((g)=>g.Id===i);if(d.S3OriginConfig={OriginAccessIdentity:""},p?.OriginAccessControlId)d.OriginAccessControlId=p.OriginAccessControlId}else d.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return r.Origins.push(d),r.OriginGroups={Quantity:1,Items:[c]},n.TargetOriginId=c.Id,bi(r),e}static setCustomDomain(e,a,r){return e.Properties.DistributionConfig.Aliases=[a],e.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:r,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},e}static setErrorPages(e,a){return e.Properties.DistributionConfig.CustomErrorResponses=a.map((r)=>({ErrorCode:r.errorCode,ResponseCode:r.responseCode,ResponsePagePath:r.responsePagePath})),e}static enableHttp3(e){return e.Properties.DistributionConfig.HttpVersion="http2and3",e}static addEdgeFunction(e,a,r){if(!e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:a,LambdaFunctionARN:r}),e}static setCachePolicy(e,a){return e.Properties.DistributionConfig.Comment=`${e.Properties.DistributionConfig.Comment||""} (TTL: ${a.default||86400}s)`,e}static createSpaDistribution(e){return Be.createDistribution({...e,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(e){let{slug:a,environment:r}=e,n=l({slug:a,environment:r,resourceType:"edge-docs"}),i=s(n),o=s(`${n}-role`),c=s(`${n}-version`),u={Type:"AWS::IAM::Role",Properties:{RoleName:`${n}-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"]}},d=`
|
|
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:n,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:P.GetAtt(o,"Arn"),Code:{ZipFile:d},MemorySize:128,Timeout:5}},role:u,functionLogicalId:i,roleLogicalId:o,versionLogicalId:c}}static createDocsDistribution(e){let{slug:a,environment:r,origin:n,customDomain:i,certificateArn:o,lambdaEdgeFunctionArn:c}=e,u=Be.createDistribution({slug:a,environment:r,origin:n,customDomain:i,certificateArn:o,comment:`Docs CDN for ${a}`,errorPages:[{errorCode:404,responseCode:404,responsePagePath:"/404.html"},{errorCode:403,responseCode:403,responsePagePath:"/404.html"}]});if(c)Be.addEdgeFunction(u.distribution,"origin-request",c);return u.distribution.Properties.DistributionConfig.DefaultCacheBehavior.DefaultTTL=86400,u.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MaxTTL=604800,u.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MinTTL=0,u}static createApiDistribution(e){let{slug:a,environment:r,albDomainName:n,customDomain:i,certificateArn:o,pathPattern:c="/api/*",forwardHeaders:u=["Host","Origin","Authorization","Content-Type","Accept"],forwardCookies:d="all",whitelistedCookies:m,customOriginHeaders:p={}}=e,g=l({slug:a,environment:r,resourceType:"cdn-api"}),h=s(g),y=Object.entries(p).map(([
|
|
139
|
+
`.trim();return{lambdaFunction:{Type:"AWS::Lambda::Function",Properties:{FunctionName:n,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:P.GetAtt(o,"Arn"),Code:{ZipFile:d},MemorySize:128,Timeout:5}},role:u,functionLogicalId:i,roleLogicalId:o,versionLogicalId:c}}static createDocsDistribution(e){let{slug:a,environment:r,origin:n,customDomain:i,certificateArn:o,lambdaEdgeFunctionArn:c}=e,u=Be.createDistribution({slug:a,environment:r,origin:n,customDomain:i,certificateArn:o,comment:`Docs CDN for ${a}`,errorPages:[{errorCode:404,responseCode:404,responsePagePath:"/404.html"},{errorCode:403,responseCode:403,responsePagePath:"/404.html"}]});if(c)Be.addEdgeFunction(u.distribution,"origin-request",c);return u.distribution.Properties.DistributionConfig.DefaultCacheBehavior.DefaultTTL=86400,u.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MaxTTL=604800,u.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MinTTL=0,u}static createApiDistribution(e){let{slug:a,environment:r,albDomainName:n,customDomain:i,certificateArn:o,pathPattern:c="/api/*",forwardHeaders:u=["Host","Origin","Authorization","Content-Type","Accept"],forwardCookies:d="all",whitelistedCookies:m,customOriginHeaders:p={}}=e,g=l({slug:a,environment:r,resourceType:"cdn-api"}),h=s(g),y=Object.entries(p).map(([T,I])=>({HeaderName:T,HeaderValue:I})),f={Id:"ALBOrigin",DomainName:n,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(y.length>0)f.OriginCustomHeaders=y;let b={Forward:d};if(d==="whitelist"&&m)b.WhitelistedNames=m;let v={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`API CDN for ${g}`,Origins:[f],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:u,Cookies:b}},PriceClass:"PriceClass_100",HttpVersion:"http2"}}};if(i&&o)v.Properties.DistributionConfig.Aliases=[i],v.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:o,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:v,logicalId:h}}static createMultiOriginDistribution(e){let{slug:a,environment:r,s3BucketDomainName:n,albDomainName:i,apiPathPattern:o="/api/*",customDomain:c,certificateArn:u,customOriginHeaders:d={}}=e,m=l({slug:a,environment:r,resourceType:"cdn"}),p=s(m),g=`${p}OAC`,h={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${m}-oac`,Description:`Origin Access Control for ${m}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},y=Object.entries(d).map(([T,I])=>({HeaderName:T,HeaderValue:I})),f={Id:"S3Origin",DomainName:n,OriginAccessControlId:P.Ref(g)},b={Id:"ALBOrigin",DomainName:i,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(y.length>0)b.OriginCustomHeaders=y;let v={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`Multi-origin CDN for ${m}`,DefaultRootObject:"index.html",Origins:[f,b],DefaultCacheBehavior:{TargetOriginId:"S3Origin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},CacheBehaviors:[{PathPattern:o,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(c&&u)v.Properties.DistributionConfig.Aliases=[c],v.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:u,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:v,originAccessControl:h,logicalId:p,oacLogicalId:g}}static addAlbOrigin(e,a){let{originId:r,domainName:n,pathPattern:i,customHeaders:o={},forwardHeaders:c=["Host","Origin","Authorization","Content-Type","Accept"],cacheTtl:u={default:0,max:0,min:0}}=a,d=Object.entries(o).map(([p,g])=>({HeaderName:p,HeaderValue:g})),m={Id:r,DomainName:n,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(d.length>0)m.OriginCustomHeaders=d;if(!e.Properties.DistributionConfig.Origins)e.Properties.DistributionConfig.Origins=[];if(e.Properties.DistributionConfig.Origins.push(m),!e.Properties.DistributionConfig.CacheBehaviors)e.Properties.DistributionConfig.CacheBehaviors=[];return e.Properties.DistributionConfig.CacheBehaviors.push({PathPattern:i,TargetOriginId:r,ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:u.default,MaxTTL:u.max,MinTTL:u.min,ForwardedValues:{QueryString:!0,Headers:c,Cookies:{Forward:"all"}}}),e}static addOriginHeader(e,a,r,n){let i=e.Properties.DistributionConfig.Origins?.find((o)=>o.Id===a);if(i){if(!i.OriginCustomHeaders)i.OriginCustomHeaders=[];i.OriginCustomHeaders.push({HeaderName:r,HeaderValue:n})}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:a=0,max:r=86400,default:n=86400}=e;return{MinTTL:a,MaxTTL:r,DefaultTTL:n}},cookies:(e,a)=>{let r={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&a)r.WhitelistedNames=a;return r},allowedMethods:(e)=>{let a={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return a[e]||a.GET_HEAD},cachedMethods:(e)=>{let a={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return a[e]||a.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:a={min:0,max:86400,default:86400},cookies:r="none",allowedCookies:n,allowedMethods:i="GET_HEAD",cachedMethods:o="GET_HEAD",compress:c=!0,forwardQueryString:u=!0,forwardHeaders:d=[]}=e;return{MinTTL:a.min,MaxTTL:a.max,DefaultTTL:a.default,Compress:c,AllowedMethods:Be.Config.allowedMethods(i),CachedMethods:Be.Config.cachedMethods(o),ForwardedValues:{QueryString:u,Headers:d,Cookies:Be.Config.cookies(r,n)}}}};static applyConfig(e,a){let r=e.Properties.DistributionConfig.DefaultCacheBehavior;if(a.ttl)r.MinTTL=a.ttl.min,r.MaxTTL=a.ttl.max,r.DefaultTTL=a.ttl.default;if(a.compress!==void 0)r.Compress=a.compress;if(a.allowedMethods)r.AllowedMethods=Be.Config.allowedMethods(a.allowedMethods);if(a.cachedMethods)r.CachedMethods=Be.Config.cachedMethods(a.cachedMethods);if(a.cookies){if(!r.ForwardedValues)r.ForwardedValues={QueryString:!0};r.ForwardedValues.Cookies=Be.Config.cookies(a.cookies,a.allowedCookies)}return e}}var _d=[403,404,500,502,503,504],Do="TsCloud::StorageFailover",ko="AllowCloudFrontFailoverRead",Yr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,Zr=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function ia(e){let{failover:a,primaryBucket:r,primaryRegion:n}=e,i=e.where??"storage failover";if(!a||typeof a!=="object")throw Error(`${i}.failover must be an object such as { region: 'us-west-2' }.`);if(!a.region||!Yr.test(a.region))throw Error(`${i}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(a.region)}.`);if(a.region===n)throw Error(`${i}.failover.region is ${a.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let o=a.bucket??`${r}-${a.region}`;if(!Zr.test(o)||o.includes("..")){let c=a.bucket===void 0&&o.length>63?` The default name (<primary bucket>-<region>) is ${o.length} characters; S3 allows 63. Set ${i}.failover.bucket.`:"";throw Error(`${i}.failover: "${o}" is not a valid S3 bucket name.${c}`)}if(o===r)throw Error(`${i}.failover.bucket must differ from the primary bucket "${r}".`);return{replicaBucket:o,replicaRegion:a.region,replicate:a.replicate!==!1,statusCodes:na(a.statusCodes??_d),primaryConnection:jt(a,`${i}.failover`)}}function oa(e,a){return`${e}.s3.${a}.amazonaws.com`}function sa(e){let a=`arn:aws:s3:::${e.primaryBucket}`,r=`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:a},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${a}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${r}/*`}]}}]}}}function aa(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 ca(e){return{Sid:ko,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function la(e){let a=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[Do];return Array.isArray(a)?a:[]}class ve{static createHostedZone(e){let{domain:a,slug:r,environment:n,comment:i}=e,o=l({slug:r,environment:n,resourceType:"hostedzone"}),c=s(`${o}-${a.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:a,HostedZoneConfig:{Comment:i||`Hosted zone for ${a}`}}},logicalId:c}}static createRecord(e){let{hostedZoneId:a,hostedZoneName:r,name:n,type:i,ttl:o,values:c,aliasTarget:u}=e,d=s(`record-${n.replace(/\./g,"")}-${i}`),m={Type:"AWS::Route53::RecordSet",Properties:{Name:n,Type:i}};if(a)m.Properties.HostedZoneId=a;else if(r)m.Properties.HostedZoneName=r;if(u)m.Properties.AliasTarget={DNSName:u.dnsName,HostedZoneId:u.hostedZoneId,EvaluateTargetHealth:u.evaluateTargetHealth??!1};else m.Properties.TTL=o||300,m.Properties.ResourceRecords=c||[];return{record:m,logicalId:d}}static createCloudFrontAlias(e,a,r){return ve.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:a,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,a,r,n){return ve.createRecord({hostedZoneId:n,name:e,type:"A",aliasTarget:{dnsName:a,hostedZoneId:r,evaluateTargetHealth:!0}})}static createCname(e,a,r,n=300){return ve.createRecord({hostedZoneId:r,name:e,type:"CNAME",ttl:n,values:[a]})}static createWwwRedirect(e,a){return ve.createRecord({hostedZoneId:a,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,a,r,n=300){return ve.createRecord({hostedZoneId:r,name:e,type:"MX",ttl:n,values:a.map((i)=>`${i.priority} ${i.server}`)})}static createTxtRecord(e,a,r,n=300){return ve.createRecord({hostedZoneId:r,name:e,type:"TXT",ttl:n,values:[`"${a}"`]})}static createSpfRecord(e,a,r){return ve.createTxtRecord(e,a,r)}static createDmarcRecord(e,a,r,n){let i=`v=DMARC1; p=${a}; rua=mailto:${r}`;return ve.createTxtRecord(`_dmarc.${e}`,i,n)}static createS3WebsiteAlias(e,a,r,n){return ve.createRecord({hostedZoneId:n,name:e,type:"A",aliasTarget:{dnsName:a,hostedZoneId:r,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,a){return`${e}.s3-website-${a}.amazonaws.com`}static createStoreRecord(e,a,r){return ve.createCname(`store.${e}`,a,r)}static createApiRecord(e,a,r){return ve.createCname(`api.${e}`,a,r)}static createDocsRecord(e,a,r){return ve.createCname(`docs.${e}`,a,r)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class j{static createCertificate(e){let{domain:a,subdomains:r=[],slug:n,environment:i,validationMethod:o="DNS",hostedZoneId:c}=e,u=l({slug:n,environment:i,resourceType:"acm"}),d=s(`${u}-${a.replace(/\./g,"")}`),m=[a];for(let g of r)if(g==="*")m.push(`*.${a}`);else m.push(`${g}.${a}`);let p={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:a,SubjectAlternativeNames:m,ValidationMethod:o}};if(o==="DNS"&&c)p.Properties.DomainValidationOptions=m.map((g)=>({DomainName:g,HostedZoneId:c}));return{certificate:p,logicalId:d}}static createKmsKey(e){let{description:a,slug:r,environment:n,enableRotation:i=!0,multiRegion:o=!1}=e,c=l({slug:r,environment:n,resourceType:"kms"}),u=s(c),d={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:P.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:"*"}]},m={Type:"AWS::KMS::Key",Properties:{Description:a,Enabled:!0,EnableKeyRotation:i,KeyPolicy:d,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:o}},p=s(`${c}-alias`),g={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${r}-${n}`,TargetKeyId:P.Ref(u)}};return{key:m,alias:g,logicalId:u,aliasId:p}}static createFirewall(e){let{slug:a,environment:r,scope:n="CLOUDFRONT",defaultAction:i="allow"}=e,o=l({slug:a,environment:r,resourceType:"waf"}),c=s(o);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:o,Scope:n,DefaultAction:i==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${a} ${r}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${o}-metric`}}},logicalId:c}}static setRateLimit(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{RateBasedStatement:{Limit:a.requestsPerWindow,AggregateKeyType:a.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static blockCountries(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{GeoMatchStatement:{CountryCodes:a.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static blockIpAddresses(e,a,r,n){let i=l({slug:r,environment:n,resourceType:"ipset"}),o=s(`${i}-${a.name}`),c={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${i}-${a.name}`,Scope:e.Properties.Scope,IPAddressVersion:a.ipVersion||"IPV4",Addresses:a.ipAddresses,Description:`Blocked IPs for ${a.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{IPSetReferenceStatement:{Arn:P.GetAtt(o,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),{webAcl:e,ipSet:c,ipSetLogicalId:o}}static addManagedRules(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];let r={ManagedRuleGroupStatement:{VendorName:a.vendorName,Name:a.ruleName}};if(a.excludedRules&&a.excludedRules.length>0)r.ManagedRuleGroupStatement.ExcludedRules=a.excludedRules.map((n)=>({Name:n}));return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:r,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.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,a){if(!e.Properties.Rules)e.Properties.Rules=[];let r=a.paths.map((n)=>({SearchString:n,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{RateBasedStatement:{Limit:a.requestsPerWindow,AggregateKeyType:a.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:r.map((n)=>({ByteMatchStatement:n}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static setHeaderRateLimit(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];let r={RateBasedStatement:{Limit:a.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:a.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(a.headerValue)r.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:a.headerValue,FieldToMatch:{SingleHeader:{Name:a.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:r,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static protectLoginEndpoint(e,a){let{loginPaths:r,priority:n,requestsPerMinute:i=10}=a;return j.setPathRateLimit(e,{name:"LoginRateLimit",priority:n,requestsPerWindow:i*5,paths:r}),e}static protectApiEndpoints(e,a){let{apiPaths:r,priority:n,requestsPerMinute:i=100}=a;return j.setPathRateLimit(e,{name:"ApiRateLimit",priority:n,requestsPerWindow:i*5,paths:r}),e}static createProtectedFirewall(e){let{slug:a,environment:r,scope:n="CLOUDFRONT",enableBotControl:i=!1,enableRateLimiting:o=!0,rateLimitPerMinute:c=2000}=e,{webAcl:u,logicalId:d}=j.createFirewall({slug:a,environment:r,scope:n,defaultAction:"allow"}),m=0;if(u=j.addManagedRules(u,{name:"AWSIPReputationList",priority:m++,...j.ManagedRuleGroups.AmazonIpReputation}),u=j.addManagedRules(u,{name:"AWSAnonymousIPList",priority:m++,...j.ManagedRuleGroups.AnonymousIpList}),u=j.addManagedRules(u,{name:"AWSCoreRuleSet",priority:m++,...j.ManagedRuleGroups.CoreRuleSet}),u=j.addManagedRules(u,{name:"AWSKnownBadInputs",priority:m++,...j.ManagedRuleGroups.KnownBadInputs}),u=j.addManagedRules(u,{name:"AWSSQLi",priority:m++,...j.ManagedRuleGroups.SqlDatabase}),i)u=j.addManagedRules(u,{name:"AWSBotControl",priority:m++,...j.ManagedRuleGroups.BotControl});if(o)u=j.setRateLimit(u,{name:"GlobalRateLimit",priority:m++,requestsPerWindow:c*5});return{webAcl:u,logicalId:d}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}class S{static createServer(e){let{slug:a,environment:r,instanceType:n="t3.micro",imageId:i="ami-0f3caa1cf4417e51b",keyName:o,securityGroupIds:c,subnetId:u,userData:d,volumeSize:m=20,volumeType:p="gp3",encrypted:g=!0}=e,h=l({slug:a,environment:r,resourceType:"ec2"}),y=s(h),f={Type:"AWS::EC2::Instance",Properties:{ImageId:i,InstanceType:n,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};if(o)f.Properties.KeyName=o;if(c)f.Properties.SecurityGroupIds=c;if(u)f.Properties.SubnetId=u;if(d)f.Properties.UserData=P.Base64(d);return f.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:g,DeleteOnTermination:!0}}],{instance:f,logicalId:y}}static createSecurityGroup(e){let{slug:a,environment:r,vpcId:n,description:i,ingress:o=[],egress:c=[]}=e,u=l({slug:a,environment:r,resourceType:"sg"}),d=s(u),m={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:i||`Security group for ${a} ${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(n)m.Properties.VpcId=n;if(o.length>0)m.Properties.SecurityGroupIngress=o.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,SourceSecurityGroupId:p.sourceSecurityGroupId}));if(c.length>0)m.Properties.SecurityGroupEgress=c.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,DestinationSecurityGroupId:p.sourceSecurityGroupId}));return{securityGroup:m,logicalId:d}}static createWebServerSecurityGroup(e,a,r){return S.createSecurityGroup({slug:e,environment:a,vpcId:r,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:a,environment:r,scheme:n="internet-facing",subnets:i,securityGroups:o,type:c="application"}=e,u=l({slug:a,environment:r,resourceType:"alb"}),d=s(u),m={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:u,Scheme:n,Type:c,Subnets:i,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(o)m.Properties.SecurityGroups=o;return{loadBalancer:m,logicalId:d}}static createTargetGroup(e){let{slug:a,environment:r,port:n,protocol:i="HTTP",vpcId:o,targetType:c="ip",healthCheckPath:u="/",healthCheckInterval:d=30,healthCheckTimeout:m=5,healthyThreshold:p=2,unhealthyThreshold:g=3}=e,h=l({slug:a,environment:r,resourceType:"tg"}),y=s(h);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:h,Port:n,Protocol:i,VpcId:o,TargetType:c,HealthCheckEnabled:!0,HealthCheckProtocol:i,HealthCheckPath:u,HealthCheckIntervalSeconds:d,HealthCheckTimeoutSeconds:m,HealthyThresholdCount:p,UnhealthyThresholdCount:g,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}},logicalId:y}}static createListener(e,a){let{port:r,protocol:n="HTTP",certificateArn:i,defaultTargetGroupArn:o}=a,c=s(`listener-${e}-${r}`),u={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:P.Ref(e),Port:r,Protocol:n,DefaultActions:[{Type:"forward",TargetGroupArn:o}]}};if(n==="HTTPS"&&i)u.Properties.Certificates=[{CertificateArn:i}],u.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:u,logicalId:c}}static createEcsCluster(e,a){let r=l({slug:e,environment:a,resourceType:"ecs-cluster"}),n=s(r);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:r,Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:a}]}},logicalId:n}}static createFargateService(e){let{slug:a,environment:r,image:n,cpu:i="256",memory:o="512",desiredCount:c=1,containerPort:u=8080,environmentVariables:d={},secrets:m=[],healthCheck:p,logGroup:g,subnets:h,securityGroups:y,targetGroupArn:f}=e,{cluster:b,logicalId:T}=S.createEcsCluster(a,r),w=l({slug:a,environment:r,resourceType:"fargate"}),I=s(`${w}-execution-role`),v={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"]}},N=s(`${w}-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"}]}}},k=s(`${w}-task`),x={Type:"AWS::ECS::TaskDefinition",Properties:{Family:w,TaskRoleArn:P.GetAtt(N,"Arn"),ExecutionRoleArn:P.GetAtt(I,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:i,Memory:o,ContainerDefinitions:[{Name:a,Image:n,Essential:!0,PortMappings:[{ContainerPort:u,Protocol:"tcp"}],Environment:Object.entries(d).map(([_,U])=>({Name:_,Value:U})),Secrets:m.map((_)=>({Name:_.name,ValueFrom:_.valueFrom}))}],Tags:[{Key:"Name",Value:w},{Key:"Environment",Value:r}]}};if(p)x.Properties.ContainerDefinitions[0].HealthCheck={Command:p.command,Interval:p.interval||30,Timeout:p.timeout||5,Retries:p.retries||3,StartPeriod:60};if(g)x.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":g,"awslogs-region":P.Ref("AWS::Region"),"awslogs-stream-prefix":a}};let M=s(`${w}-service`),B={Type:"AWS::ECS::Service",Properties:{ServiceName:w,Cluster:P.Ref(T),TaskDefinition:P.Ref(k),DesiredCount:c,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:h,SecurityGroups:y,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:w},{Key:"Environment",Value:r}]}};if(f)B.Properties.LoadBalancers=[{TargetGroupArn:f,ContainerName:a,ContainerPort:u}];return{cluster:b,taskDefinition:x,service:B,taskRole:R,executionRole:v,clusterLogicalId:T,taskDefinitionLogicalId:k,serviceLogicalId:M,taskRoleLogicalId:N,executionRoleLogicalId:I}}static createLambdaFunction(e){let{slug:a,environment:r,runtime:n,handler:i,code:o,timeout:c=30,memorySize:u=128,environmentVariables:d={},vpcConfig:m}=e,p=l({slug:a,environment:r,resourceType:"lambda"}),g=s(p),h=s(`${p}-role`),y={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(m)y.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let f={Type:"AWS::Lambda::Function",Properties:{FunctionName:p,Runtime:n,Role:P.GetAtt(h,"Arn"),Handler:i,Code:{...o.s3Bucket&&{S3Bucket:o.s3Bucket},...o.s3Key&&{S3Key:o.s3Key},...o.zipFile&&{ZipFile:o.zipFile}},Timeout:c,MemorySize:u,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r}]}};if(Object.keys(d).length>0)f.Properties.Environment={Variables:d};if(m)f.Properties.VpcConfig={SecurityGroupIds:m.securityGroupIds,SubnetIds:m.subnetIds};return{lambdaFunction:f,role:y,logicalId:g,roleLogicalId:h}}static generateNodeServerUserData(e={}){let{nodeVersion:a="20",appRepo:r,environment:n={}}=e,i=Object.entries(n).map(([o,c])=>`echo "export ${o}='${c}'" >> /etc/environment`).join(`
|
|
212
|
+
`.trim()};static Config={ttl:(e)=>{let{min:a=0,max:r=86400,default:n=86400}=e;return{MinTTL:a,MaxTTL:r,DefaultTTL:n}},cookies:(e,a)=>{let r={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&a)r.WhitelistedNames=a;return r},allowedMethods:(e)=>{let a={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return a[e]||a.GET_HEAD},cachedMethods:(e)=>{let a={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return a[e]||a.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:a={min:0,max:86400,default:86400},cookies:r="none",allowedCookies:n,allowedMethods:i="GET_HEAD",cachedMethods:o="GET_HEAD",compress:c=!0,forwardQueryString:u=!0,forwardHeaders:d=[]}=e;return{MinTTL:a.min,MaxTTL:a.max,DefaultTTL:a.default,Compress:c,AllowedMethods:Be.Config.allowedMethods(i),CachedMethods:Be.Config.cachedMethods(o),ForwardedValues:{QueryString:u,Headers:d,Cookies:Be.Config.cookies(r,n)}}}};static applyConfig(e,a){let r=e.Properties.DistributionConfig.DefaultCacheBehavior;if(a.ttl)r.MinTTL=a.ttl.min,r.MaxTTL=a.ttl.max,r.DefaultTTL=a.ttl.default;if(a.compress!==void 0)r.Compress=a.compress;if(a.allowedMethods)r.AllowedMethods=Be.Config.allowedMethods(a.allowedMethods);if(a.cachedMethods)r.CachedMethods=Be.Config.cachedMethods(a.cachedMethods);if(a.cookies){if(!r.ForwardedValues)r.ForwardedValues={QueryString:!0};r.ForwardedValues.Cookies=Be.Config.cookies(a.cookies,a.allowedCookies)}return e}}var _d=[403,404,500,502,503,504],Do="TsCloud::StorageFailover",ko="AllowCloudFrontFailoverRead",Yr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,Zr=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function ia(e){let{failover:a,primaryBucket:r,primaryRegion:n}=e,i=e.where??"storage failover";if(!a||typeof a!=="object")throw Error(`${i}.failover must be an object such as { region: 'us-west-2' }.`);if(!a.region||!Yr.test(a.region))throw Error(`${i}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(a.region)}.`);if(a.region===n)throw Error(`${i}.failover.region is ${a.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let o=a.bucket??`${r}-${a.region}`;if(!Zr.test(o)||o.includes("..")){let c=a.bucket===void 0&&o.length>63?` The default name (<primary bucket>-<region>) is ${o.length} characters; S3 allows 63. Set ${i}.failover.bucket.`:"";throw Error(`${i}.failover: "${o}" is not a valid S3 bucket name.${c}`)}if(o===r)throw Error(`${i}.failover.bucket must differ from the primary bucket "${r}".`);return{replicaBucket:o,replicaRegion:a.region,replicate:a.replicate!==!1,statusCodes:na(a.statusCodes??_d),primaryConnection:jt(a,`${i}.failover`)}}function oa(e,a){return`${e}.s3.${a}.amazonaws.com`}function sa(e){let a=`arn:aws:s3:::${e.primaryBucket}`,r=`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:a},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${a}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${r}/*`}]}}]}}}function aa(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 ca(e){return{Sid:ko,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function la(e){let a=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[Do];return Array.isArray(a)?a:[]}class ve{static createHostedZone(e){let{domain:a,slug:r,environment:n,comment:i}=e,o=l({slug:r,environment:n,resourceType:"hostedzone"}),c=s(`${o}-${a.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:a,HostedZoneConfig:{Comment:i||`Hosted zone for ${a}`}}},logicalId:c}}static createRecord(e){let{hostedZoneId:a,hostedZoneName:r,name:n,type:i,ttl:o,values:c,aliasTarget:u}=e,d=s(`record-${n.replace(/\./g,"")}-${i}`),m={Type:"AWS::Route53::RecordSet",Properties:{Name:n,Type:i}};if(a)m.Properties.HostedZoneId=a;else if(r)m.Properties.HostedZoneName=r;if(u)m.Properties.AliasTarget={DNSName:u.dnsName,HostedZoneId:u.hostedZoneId,EvaluateTargetHealth:u.evaluateTargetHealth??!1};else m.Properties.TTL=o||300,m.Properties.ResourceRecords=c||[];return{record:m,logicalId:d}}static createCloudFrontAlias(e,a,r){return ve.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:a,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,a,r,n){return ve.createRecord({hostedZoneId:n,name:e,type:"A",aliasTarget:{dnsName:a,hostedZoneId:r,evaluateTargetHealth:!0}})}static createCname(e,a,r,n=300){return ve.createRecord({hostedZoneId:r,name:e,type:"CNAME",ttl:n,values:[a]})}static createWwwRedirect(e,a){return ve.createRecord({hostedZoneId:a,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,a,r,n=300){return ve.createRecord({hostedZoneId:r,name:e,type:"MX",ttl:n,values:a.map((i)=>`${i.priority} ${i.server}`)})}static createTxtRecord(e,a,r,n=300){return ve.createRecord({hostedZoneId:r,name:e,type:"TXT",ttl:n,values:[`"${a}"`]})}static createSpfRecord(e,a,r){return ve.createTxtRecord(e,a,r)}static createDmarcRecord(e,a,r,n){let i=`v=DMARC1; p=${a}; rua=mailto:${r}`;return ve.createTxtRecord(`_dmarc.${e}`,i,n)}static createS3WebsiteAlias(e,a,r,n){return ve.createRecord({hostedZoneId:n,name:e,type:"A",aliasTarget:{dnsName:a,hostedZoneId:r,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,a){return`${e}.s3-website-${a}.amazonaws.com`}static createStoreRecord(e,a,r){return ve.createCname(`store.${e}`,a,r)}static createApiRecord(e,a,r){return ve.createCname(`api.${e}`,a,r)}static createDocsRecord(e,a,r){return ve.createCname(`docs.${e}`,a,r)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class j{static createCertificate(e){let{domain:a,subdomains:r=[],slug:n,environment:i,validationMethod:o="DNS",hostedZoneId:c}=e,u=l({slug:n,environment:i,resourceType:"acm"}),d=s(`${u}-${a.replace(/\./g,"")}`),m=[a];for(let g of r)if(g==="*")m.push(`*.${a}`);else m.push(`${g}.${a}`);let p={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:a,SubjectAlternativeNames:m,ValidationMethod:o}};if(o==="DNS"&&c)p.Properties.DomainValidationOptions=m.map((g)=>({DomainName:g,HostedZoneId:c}));return{certificate:p,logicalId:d}}static createKmsKey(e){let{description:a,slug:r,environment:n,enableRotation:i=!0,multiRegion:o=!1}=e,c=l({slug:r,environment:n,resourceType:"kms"}),u=s(c),d={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:P.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:"*"}]},m={Type:"AWS::KMS::Key",Properties:{Description:a,Enabled:!0,EnableKeyRotation:i,KeyPolicy:d,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:o}},p=s(`${c}-alias`),g={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${r}-${n}`,TargetKeyId:P.Ref(u)}};return{key:m,alias:g,logicalId:u,aliasId:p}}static createFirewall(e){let{slug:a,environment:r,scope:n="CLOUDFRONT",defaultAction:i="allow"}=e,o=l({slug:a,environment:r,resourceType:"waf"}),c=s(o);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:o,Scope:n,DefaultAction:i==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${a} ${r}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${o}-metric`}}},logicalId:c}}static setRateLimit(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{RateBasedStatement:{Limit:a.requestsPerWindow,AggregateKeyType:a.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static blockCountries(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{GeoMatchStatement:{CountryCodes:a.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static blockIpAddresses(e,a,r,n){let i=l({slug:r,environment:n,resourceType:"ipset"}),o=s(`${i}-${a.name}`),c={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${i}-${a.name}`,Scope:e.Properties.Scope,IPAddressVersion:a.ipVersion||"IPV4",Addresses:a.ipAddresses,Description:`Blocked IPs for ${a.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{IPSetReferenceStatement:{Arn:P.GetAtt(o,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),{webAcl:e,ipSet:c,ipSetLogicalId:o}}static addManagedRules(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];let r={ManagedRuleGroupStatement:{VendorName:a.vendorName,Name:a.ruleName}};if(a.excludedRules&&a.excludedRules.length>0)r.ManagedRuleGroupStatement.ExcludedRules=a.excludedRules.map((n)=>({Name:n}));return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:r,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.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,a){if(!e.Properties.Rules)e.Properties.Rules=[];let r=a.paths.map((n)=>({SearchString:n,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:{RateBasedStatement:{Limit:a.requestsPerWindow,AggregateKeyType:a.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:r.map((n)=>({ByteMatchStatement:n}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static setHeaderRateLimit(e,a){if(!e.Properties.Rules)e.Properties.Rules=[];let r={RateBasedStatement:{Limit:a.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:a.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(a.headerValue)r.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:a.headerValue,FieldToMatch:{SingleHeader:{Name:a.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:a.name,Priority:a.priority,Statement:r,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a.name}-metric`}}),e}static protectLoginEndpoint(e,a){let{loginPaths:r,priority:n,requestsPerMinute:i=10}=a;return j.setPathRateLimit(e,{name:"LoginRateLimit",priority:n,requestsPerWindow:i*5,paths:r}),e}static protectApiEndpoints(e,a){let{apiPaths:r,priority:n,requestsPerMinute:i=100}=a;return j.setPathRateLimit(e,{name:"ApiRateLimit",priority:n,requestsPerWindow:i*5,paths:r}),e}static createProtectedFirewall(e){let{slug:a,environment:r,scope:n="CLOUDFRONT",enableBotControl:i=!1,enableRateLimiting:o=!0,rateLimitPerMinute:c=2000}=e,{webAcl:u,logicalId:d}=j.createFirewall({slug:a,environment:r,scope:n,defaultAction:"allow"}),m=0;if(u=j.addManagedRules(u,{name:"AWSIPReputationList",priority:m++,...j.ManagedRuleGroups.AmazonIpReputation}),u=j.addManagedRules(u,{name:"AWSAnonymousIPList",priority:m++,...j.ManagedRuleGroups.AnonymousIpList}),u=j.addManagedRules(u,{name:"AWSCoreRuleSet",priority:m++,...j.ManagedRuleGroups.CoreRuleSet}),u=j.addManagedRules(u,{name:"AWSKnownBadInputs",priority:m++,...j.ManagedRuleGroups.KnownBadInputs}),u=j.addManagedRules(u,{name:"AWSSQLi",priority:m++,...j.ManagedRuleGroups.SqlDatabase}),i)u=j.addManagedRules(u,{name:"AWSBotControl",priority:m++,...j.ManagedRuleGroups.BotControl});if(o)u=j.setRateLimit(u,{name:"GlobalRateLimit",priority:m++,requestsPerWindow:c*5});return{webAcl:u,logicalId:d}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}class S{static createServer(e){let{slug:a,environment:r,instanceType:n="t3.micro",imageId:i="ami-0f3caa1cf4417e51b",keyName:o,securityGroupIds:c,subnetId:u,userData:d,volumeSize:m=20,volumeType:p="gp3",encrypted:g=!0}=e,h=l({slug:a,environment:r,resourceType:"ec2"}),y=s(h),f={Type:"AWS::EC2::Instance",Properties:{ImageId:i,InstanceType:n,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};if(o)f.Properties.KeyName=o;if(c)f.Properties.SecurityGroupIds=c;if(u)f.Properties.SubnetId=u;if(d)f.Properties.UserData=P.Base64(d);return f.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:g,DeleteOnTermination:!0}}],{instance:f,logicalId:y}}static createSecurityGroup(e){let{slug:a,environment:r,vpcId:n,description:i,ingress:o=[],egress:c=[]}=e,u=l({slug:a,environment:r,resourceType:"sg"}),d=s(u),m={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:i||`Security group for ${a} ${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(n)m.Properties.VpcId=n;if(o.length>0)m.Properties.SecurityGroupIngress=o.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,SourceSecurityGroupId:p.sourceSecurityGroupId}));if(c.length>0)m.Properties.SecurityGroupEgress=c.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,DestinationSecurityGroupId:p.sourceSecurityGroupId}));return{securityGroup:m,logicalId:d}}static createWebServerSecurityGroup(e,a,r){return S.createSecurityGroup({slug:e,environment:a,vpcId:r,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:a,environment:r,scheme:n="internet-facing",subnets:i,securityGroups:o,type:c="application"}=e,u=l({slug:a,environment:r,resourceType:"alb"}),d=s(u),m={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:u,Scheme:n,Type:c,Subnets:i,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(o)m.Properties.SecurityGroups=o;return{loadBalancer:m,logicalId:d}}static createTargetGroup(e){let{slug:a,environment:r,port:n,protocol:i="HTTP",vpcId:o,targetType:c="ip",healthCheckPath:u="/",healthCheckInterval:d=30,healthCheckTimeout:m=5,healthyThreshold:p=2,unhealthyThreshold:g=3}=e,h=l({slug:a,environment:r,resourceType:"tg"}),y=s(h);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:h,Port:n,Protocol:i,VpcId:o,TargetType:c,HealthCheckEnabled:!0,HealthCheckProtocol:i,HealthCheckPath:u,HealthCheckIntervalSeconds:d,HealthCheckTimeoutSeconds:m,HealthyThresholdCount:p,UnhealthyThresholdCount:g,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}},logicalId:y}}static createListener(e,a){let{port:r,protocol:n="HTTP",certificateArn:i,defaultTargetGroupArn:o}=a,c=s(`listener-${e}-${r}`),u={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:P.Ref(e),Port:r,Protocol:n,DefaultActions:[{Type:"forward",TargetGroupArn:o}]}};if(n==="HTTPS"&&i)u.Properties.Certificates=[{CertificateArn:i}],u.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:u,logicalId:c}}static createEcsCluster(e,a){let r=l({slug:e,environment:a,resourceType:"ecs-cluster"}),n=s(r);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:r,Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:a}]}},logicalId:n}}static createFargateService(e){let{slug:a,environment:r,image:n,cpu:i="256",memory:o="512",desiredCount:c=1,containerPort:u=8080,environmentVariables:d={},secrets:m=[],healthCheck:p,logGroup:g,subnets:h,securityGroups:y,targetGroupArn:f}=e,{cluster:b,logicalId:v}=S.createEcsCluster(a,r),T=l({slug:a,environment:r,resourceType:"fargate"}),I=s(`${T}-execution-role`),C={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"]}},N=s(`${T}-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"}]}}},k=s(`${T}-task`),x={Type:"AWS::ECS::TaskDefinition",Properties:{Family:T,TaskRoleArn:P.GetAtt(N,"Arn"),ExecutionRoleArn:P.GetAtt(I,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:i,Memory:o,ContainerDefinitions:[{Name:a,Image:n,Essential:!0,PortMappings:[{ContainerPort:u,Protocol:"tcp"}],Environment:Object.entries(d).map(([_,U])=>({Name:_,Value:U})),Secrets:m.map((_)=>({Name:_.name,ValueFrom:_.valueFrom}))}],Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:r}]}};if(p)x.Properties.ContainerDefinitions[0].HealthCheck={Command:p.command,Interval:p.interval||30,Timeout:p.timeout||5,Retries:p.retries||3,StartPeriod:60};if(g)x.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":g,"awslogs-region":P.Ref("AWS::Region"),"awslogs-stream-prefix":a}};let M=s(`${T}-service`),B={Type:"AWS::ECS::Service",Properties:{ServiceName:T,Cluster:P.Ref(v),TaskDefinition:P.Ref(k),DesiredCount:c,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:h,SecurityGroups:y,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:r}]}};if(f)B.Properties.LoadBalancers=[{TargetGroupArn:f,ContainerName:a,ContainerPort:u}];return{cluster:b,taskDefinition:x,service:B,taskRole:R,executionRole:C,clusterLogicalId:v,taskDefinitionLogicalId:k,serviceLogicalId:M,taskRoleLogicalId:N,executionRoleLogicalId:I}}static createLambdaFunction(e){let{slug:a,environment:r,runtime:n,handler:i,code:o,timeout:c=30,memorySize:u=128,environmentVariables:d={},vpcConfig:m}=e,p=l({slug:a,environment:r,resourceType:"lambda"}),g=s(p),h=s(`${p}-role`),y={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(m)y.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let f={Type:"AWS::Lambda::Function",Properties:{FunctionName:p,Runtime:n,Role:P.GetAtt(h,"Arn"),Handler:i,Code:{...o.s3Bucket&&{S3Bucket:o.s3Bucket},...o.s3Key&&{S3Key:o.s3Key},...o.zipFile&&{ZipFile:o.zipFile}},Timeout:c,MemorySize:u,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r}]}};if(Object.keys(d).length>0)f.Properties.Environment={Variables:d};if(m)f.Properties.VpcConfig={SecurityGroupIds:m.securityGroupIds,SubnetIds:m.subnetIds};return{lambdaFunction:f,role:y,logicalId:g,roleLogicalId:h}}static generateNodeServerUserData(e={}){let{nodeVersion:a="20",appRepo:r,environment:n={}}=e,i=Object.entries(n).map(([o,c])=>`echo "export ${o}='${c}'" >> /etc/environment`).join(`
|
|
213
213
|
`);return`#!/bin/bash
|
|
214
214
|
# Update system
|
|
215
215
|
yum update -y
|
|
@@ -310,15 +310,15 @@ systemctl enable caddy
|
|
|
310
310
|
systemctl start caddy
|
|
311
311
|
|
|
312
312
|
echo "Bun server setup complete!"
|
|
313
|
-
`}static createLaunchConfiguration(e){let{slug:a,environment:r,imageId:n,instanceType:i,keyName:o,securityGroups:c,userData:u,volumeSize:d=20,volumeType:m="gp3",encrypted:p=!0,iamInstanceProfile:g}=e,h=l({slug:a,environment:r,resourceType:"launch-config"}),y=s(h),f={Type:"AWS::AutoScaling::LaunchConfiguration",Properties:{ImageId:n,InstanceType:i,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:d,VolumeType:m,Encrypted:p,DeleteOnTermination:!0}}]}};if(o)f.Properties.KeyName=o;if(c)f.Properties.SecurityGroups=c;if(u)f.Properties.UserData=P.Base64(u);if(g)f.Properties.IamInstanceProfile=g;return{launchConfiguration:f,logicalId:y}}static createAutoScalingGroup(e){let{slug:a,environment:r,launchConfigurationName:n,minSize:i,maxSize:o,desiredCapacity:c,vpcZoneIdentifier:u,targetGroupArns:d,healthCheckType:m="EC2",healthCheckGracePeriod:p=300,cooldown:g=300,tags:h={}}=e,y=l({slug:a,environment:r,resourceType:"asg"}),f=s(y),b={Type:"AWS::AutoScaling::AutoScalingGroup",Properties:{AutoScalingGroupName:y,LaunchConfigurationName:n,MinSize:i,MaxSize:o,HealthCheckType:m,HealthCheckGracePeriod:p,Cooldown:g,Tags:[{Key:"Name",Value:y,PropagateAtLaunch:!0},{Key:"Environment",Value:r,PropagateAtLaunch:!0},...Object.entries(h).map(([T
|
|
313
|
+
`}static createLaunchConfiguration(e){let{slug:a,environment:r,imageId:n,instanceType:i,keyName:o,securityGroups:c,userData:u,volumeSize:d=20,volumeType:m="gp3",encrypted:p=!0,iamInstanceProfile:g}=e,h=l({slug:a,environment:r,resourceType:"launch-config"}),y=s(h),f={Type:"AWS::AutoScaling::LaunchConfiguration",Properties:{ImageId:n,InstanceType:i,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:d,VolumeType:m,Encrypted:p,DeleteOnTermination:!0}}]}};if(o)f.Properties.KeyName=o;if(c)f.Properties.SecurityGroups=c;if(u)f.Properties.UserData=P.Base64(u);if(g)f.Properties.IamInstanceProfile=g;return{launchConfiguration:f,logicalId:y}}static createAutoScalingGroup(e){let{slug:a,environment:r,launchConfigurationName:n,minSize:i,maxSize:o,desiredCapacity:c,vpcZoneIdentifier:u,targetGroupArns:d,healthCheckType:m="EC2",healthCheckGracePeriod:p=300,cooldown:g=300,tags:h={}}=e,y=l({slug:a,environment:r,resourceType:"asg"}),f=s(y),b={Type:"AWS::AutoScaling::AutoScalingGroup",Properties:{AutoScalingGroupName:y,LaunchConfigurationName:n,MinSize:i,MaxSize:o,HealthCheckType:m,HealthCheckGracePeriod:p,Cooldown:g,Tags:[{Key:"Name",Value:y,PropagateAtLaunch:!0},{Key:"Environment",Value:r,PropagateAtLaunch:!0},...Object.entries(h).map(([v,T])=>({Key:v,Value:T,PropagateAtLaunch:!0}))]}};if(c!==void 0)b.Properties.DesiredCapacity=c;if(u)b.Properties.VPCZoneIdentifier=u;if(d)b.Properties.TargetGroupARNs=d;return b.UpdatePolicy={AutoScalingRollingUpdate:{MaxBatchSize:1,MinInstancesInService:Math.max(0,i-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:b,logicalId:f}}static createScalingPolicy(e){let{slug:a,environment:r,autoScalingGroupName:n,policyType:i="TargetTrackingScaling",targetValue:o=70,predefinedMetricType:c="ASGAverageCPUUtilization"}=e,u=l({slug:a,environment:r,resourceType:"scaling-policy"}),d=s(u),m={Type:"AWS::AutoScaling::ScalingPolicy",Properties:{AutoScalingGroupName:n,PolicyType:i}};if(i==="TargetTrackingScaling")m.Properties.TargetTrackingConfiguration={PredefinedMetricSpecification:{PredefinedMetricType:c},TargetValue:o};return{scalingPolicy:m,logicalId:d}}static AutoScaling={smallWebServer:(e,a,r,n,i)=>S.createAutoScalingGroup({slug:e,environment:a,launchConfigurationName:r,minSize:2,maxSize:4,desiredCapacity:2,vpcZoneIdentifier:n,targetGroupArns:i,healthCheckType:i?"ELB":"EC2",healthCheckGracePeriod:300}),mediumWebServer:(e,a,r,n,i)=>S.createAutoScalingGroup({slug:e,environment:a,launchConfigurationName:r,minSize:3,maxSize:10,desiredCapacity:3,vpcZoneIdentifier:n,targetGroupArns:i,healthCheckType:i?"ELB":"EC2",healthCheckGracePeriod:300}),largeWebServer:(e,a,r,n,i)=>S.createAutoScalingGroup({slug:e,environment:a,launchConfigurationName:r,minSize:5,maxSize:20,desiredCapacity:5,vpcZoneIdentifier:n,targetGroupArns:i,healthCheckType:i?"ELB":"EC2",healthCheckGracePeriod:300}),cpuScaling:(e,a,r,n=70)=>S.createScalingPolicy({slug:e,environment:a,autoScalingGroupName:r,policyType:"TargetTrackingScaling",predefinedMetricType:"ASGAverageCPUUtilization",targetValue:n}),requestCountScaling:(e,a,r,n=1000)=>S.createScalingPolicy({slug:e,environment:a,autoScalingGroupName:r,policyType:"TargetTrackingScaling",predefinedMetricType:"ALBRequestCountPerTarget",targetValue:n})};static Secrets={fromSecretsManager:(e)=>Object.entries(e).map(([a,r])=>({name:a,valueFrom:r})),fromJsonSecret:(e,a)=>`${e}:${a}::`,fromSecretVersion:(e,a)=>`${e}::${a}:`,fromSecretVersionStage:(e,a)=>`${e}:::${a}`,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 a=e.region||"*",r=e.accountId||"*";return`arn:aws:secretsmanager:${a}:${r}: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:a=[],kmsKeyArns:r=[],...n}=e,i=S.createFargateService(n);if(a.length>0){if(!i.executionRole.Properties.Policies)i.executionRole.Properties.Policies=[];if(i.executionRole.Properties.Policies.push(S.Secrets.createAccessPolicy(a)),r.length>0)i.executionRole.Properties.Policies.push(S.Secrets.createKmsPolicy(r))}return i}static generateSecretReferences(e){return e.secrets.map((a)=>{let r=`arn:aws:secretsmanager:${e.region}:${e.accountId}:secret:${e.secretPrefix}/${a}`;return{name:a.toUpperCase().replace(/-/g,"_"),valueFrom:r}})}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:a,environment:r,vpcId:n,subnetId:i,keyName:o,instanceType:c="t3.micro",imageId:u="ami-0f3caa1cf4417e51b",allowedCidrs:d=["0.0.0.0/0"],mountEfs:m}=e,p=l({slug:a,environment:r,resourceType:"jumpbox"}),g=s(`${p}-sg`),h={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:`${p}-sg`,GroupDescription:`Security group for ${p} JumpBox SSH access`,VpcId:n,SecurityGroupIngress:d.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:`${p}-sg`},{Key:"Environment",Value:r}]}},y=s(`${p}-role`),f={Type:"AWS::IAM::Role",Properties:{RoleName:`${p}-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:m?[{PolicyName:"EFSAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess"],Resource:"*"}]}}]:void 0}},b=s(`${p}-profile`),v={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:`${p}-profile`,Roles:[P.Ref(y)]}},T=`#!/bin/bash
|
|
314
314
|
yum update -y
|
|
315
315
|
yum install -y amazon-efs-utils nfs-utils jq curl wget htop
|
|
316
|
-
`;if(m){let R=m.mountPath||"/mnt/efs";
|
|
316
|
+
`;if(m){let R=m.mountPath||"/mnt/efs";T+=`
|
|
317
317
|
# Mount EFS
|
|
318
318
|
mkdir -p ${R}
|
|
319
319
|
mount -t efs ${m.fileSystemId}:/ ${R}
|
|
320
320
|
echo "${m.fileSystemId}:/ ${R} efs defaults,_netdev 0 0" >> /etc/fstab
|
|
321
|
-
`}let I=s(p),
|
|
321
|
+
`}let I=s(p),C={Type:"AWS::EC2::Instance",DependsOn:[b],Properties:{ImageId:u,InstanceType:c,KeyName:o,SubnetId:i,SecurityGroupIds:[P.Ref(g)],IamInstanceProfile:P.Ref(b),UserData:P.Base64(T),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Purpose",Value:"JumpBox/Bastion"}]}},N={[g]:h,[y]:f,[b]:v,[I]:C};return{instance:C,securityGroup:h,instanceProfile:v,instanceRole:f,instanceLogicalId:I,securityGroupLogicalId:g,instanceProfileLogicalId:b,instanceRoleLogicalId:y,resources:N}}static JumpBox={withEfsMount:(e)=>S.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)=>S.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 a=S.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,allowedCidrs:e.allowedCidrs}),r=`#!/bin/bash
|
|
322
322
|
yum update -y
|
|
323
323
|
yum install -y amazon-efs-utils nfs-utils jq curl wget htop
|
|
324
324
|
|
|
@@ -604,7 +604,7 @@ ufw default allow outgoing
|
|
|
604
604
|
${e.map((a)=>`ufw allow ${a}`).join(`
|
|
605
605
|
`)}
|
|
606
606
|
ufw --force enable
|
|
607
|
-
`},Presets:{bunWithNginx:(e,a=3000)=>S.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:e,appPort:a,enableSsl:!0}),bunWithCaddy:(e,a=3000)=>S.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:e,appPort:a,enableSsl:!1}),nodeWithPm2:(e,a=3000)=>S.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:e,appPort:a,enableSsl:!0}),worker:(e="bun")=>S.UserData.generateAppServerScript({runtime:e,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(e){let{slug:a,environment:r,domain:n,instanceLogicalId:i}=e,o=l({slug:a,environment:r,resourceType:"eip"}),c=s(o),u={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r},...n?[{Key:"Domain",Value:n}]:[]]}},d={[c]:u},m,p;if(i)p=s(`${o}-assoc`),m={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:P.GetAtt(c,"AllocationId"),InstanceId:P.Ref(i)}},d[p]=m;return{eip:u,eipAssociation:m,eipLogicalId:c,associationLogicalId:p,resources:d}}static createServerModeStack(e){let{slug:a,environment:r,vpcId:n,subnetId:i,instanceType:o="t3.small",imageId:c="ami-0f3caa1cf4417e51b",keyName:u,domain:d,userData:m,allowedPorts:p=[22,80,443],volumeSize:g=20,volumeType:h="gp3"}=e,y={},f=l({slug:a,environment:r,resourceType:"server-sg"}),b=s(f),
|
|
607
|
+
`},Presets:{bunWithNginx:(e,a=3000)=>S.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:e,appPort:a,enableSsl:!0}),bunWithCaddy:(e,a=3000)=>S.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:e,appPort:a,enableSsl:!1}),nodeWithPm2:(e,a=3000)=>S.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:e,appPort:a,enableSsl:!0}),worker:(e="bun")=>S.UserData.generateAppServerScript({runtime:e,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(e){let{slug:a,environment:r,domain:n,instanceLogicalId:i}=e,o=l({slug:a,environment:r,resourceType:"eip"}),c=s(o),u={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r},...n?[{Key:"Domain",Value:n}]:[]]}},d={[c]:u},m,p;if(i)p=s(`${o}-assoc`),m={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:P.GetAtt(c,"AllocationId"),InstanceId:P.Ref(i)}},d[p]=m;return{eip:u,eipAssociation:m,eipLogicalId:c,associationLogicalId:p,resources:d}}static createServerModeStack(e){let{slug:a,environment:r,vpcId:n,subnetId:i,instanceType:o="t3.small",imageId:c="ami-0f3caa1cf4417e51b",keyName:u,domain:d,userData:m,allowedPorts:p=[22,80,443],volumeSize:g=20,volumeType:h="gp3"}=e,y={},f=l({slug:a,environment:r,resourceType:"server-sg"}),b=s(f),v={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:f,GroupDescription:`Security group for ${a} server`,VpcId:n,SecurityGroupIngress:p.map((V)=>({IpProtocol:"tcp",FromPort:V,ToPort:V,CidrIp:"0.0.0.0/0",Description:`Port ${V}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:r}]}};y[b]=v;let T=l({slug:a,environment:r,resourceType:"server-role"}),I=s(T),C={Type:"AWS::IAM::Role",Properties:{RoleName:T,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:"*"}]}}]}};y[I]=C;let N=l({slug:a,environment:r,resourceType:"server-profile"}),R=s(N),k={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:N,Roles:[P.Ref(I)]}};y[R]=k;let x=l({slug:a,environment:r,resourceType:"server"}),M=s(x),B={Type:"AWS::EC2::Instance",DependsOn:[R],Properties:{ImageId:c,InstanceType:o,KeyName:u,SubnetId:i,SecurityGroupIds:[P.Ref(b)],IamInstanceProfile:P.Ref(R),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:g,VolumeType:h,Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:x},{Key:"Environment",Value:r},...d?[{Key:"Domain",Value:d}]:[]]}};if(m)B.Properties.UserData=P.Base64(m);y[M]=B;let{eip:_,eipAssociation:U,eipLogicalId:Y,associationLogicalId:q,resources:Q}=S.createElasticIp({slug:a,environment:r,domain:d,instanceLogicalId:M});return Object.assign(y,Q),{instance:B,securityGroup:v,eip:_,eipAssociation:U,instanceRole:C,instanceProfile:k,resources:y,outputs:{instanceLogicalId:M,securityGroupLogicalId:b,eipLogicalId:Y,associationLogicalId:q,roleLogicalId:I,profileLogicalId:R}}}static ServerMode={webServer:(e)=>{let a=S.UserData.generateAppServerScript({runtime:e.runtime||"bun",webServer:e.webServer||"nginx",domain:e.domain,enableSsl:!0});return S.createServerModeStack({...e,userData:a,instanceType:"t3.small",allowedPorts:[22,80,443]})},workerServer:(e)=>{let a=S.UserData.generateAppServerScript({runtime:e.runtime||"bun",webServer:"none",installRedis:e.installRedis});return S.createServerModeStack({...e,userData:a,instanceType:"t3.medium",allowedPorts:[22]})},cacheServer:(e)=>S.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 L{static createVpc(e){let{slug:a,environment:r,cidr:n="10.0.0.0/16",enableDnsHostnames:i=!0,enableDnsSupport:o=!0}=e,c=l({slug:a,environment:r,resourceType:"vpc"}),u=s(c);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:n,EnableDnsHostnames:i,EnableDnsSupport:o,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}},logicalId:u}}static createSubnet(e){let{slug:a,environment:r,vpcId:n,type:i,cidr:o,availabilityZone:c,mapPublicIp:u=i==="public"}=e,d=l({slug:a,environment:r,resourceType:`subnet-${i}`}),m=s(`${d}-${c}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:n,CidrBlock:o,AvailabilityZone:c,MapPublicIpOnLaunch:u,Tags:[{Key:"Name",Value:`${d}-${c}`},{Key:"Environment",Value:r},{Key:"Type",Value:i}]}},logicalId:m}}static createInternetGateway(e,a){let r=l({slug:e,environment:a,resourceType:"igw"}),n=s(r);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:a}]}},logicalId:n}}static attachInternetGateway(e,a){let r=s(`${e}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:P.Ref(e),InternetGatewayId:P.Ref(a)}},logicalId:r}}static createEip(e,a){let r=l({slug:e,environment:a,resourceType:"eip"}),n=s(r);return{eip:{Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:a}]}},logicalId:n}}static createNatGateway(e,a){let{slug:r,environment:n,subnetId:i}=e,o=l({slug:r,environment:n,resourceType:"nat"}),c=s(o);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:P.GetAtt(a,"AllocationId"),SubnetId:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:c}}static createRouteTable(e,a,r,n){let i=l({slug:e,environment:a,resourceType:`rt-${n}`}),o=s(i);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:P.Ref(r),Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:a},{Key:"Type",Value:n}]}},logicalId:o}}static createRoute(e,a,r){let n=s(`${e}-route-${r.type}`),i={Type:"AWS::EC2::Route",Properties:{RouteTableId:P.Ref(e),DestinationCidrBlock:a}};if(r.type==="igw")i.Properties.GatewayId=P.Ref(r.logicalId);else if(r.type==="nat")i.Properties.NatGatewayId=P.Ref(r.logicalId);else if(r.type==="instance")i.Properties.InstanceId=P.Ref(r.logicalId);return{route:i,logicalId:n}}static associateSubnetWithRouteTable(e,a){let r=s(`${e}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:P.Ref(e),RouteTableId:P.Ref(a)}},logicalId:r}}static enableFlowLogs(e){let{slug:a,environment:r,resourceId:n,resourceType:i,trafficType:o="ALL",logGroupName:c}=e,u=l({slug:a,environment:r,resourceType:"flowlog"}),d=s(u);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:i,ResourceIds:[n],TrafficType:o,LogDestinationType:"cloud-watch-logs",LogGroupName:c||`/aws/vpc/${a}-${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static calculateSubnetCidrs(e,a,r=3){let[n,i]=e.split("/"),o=Number.parseInt(i,10),c=Math.ceil(Math.log2(a*r)),u=o+c;if(u>28)throw Error("VPC CIDR is too small to accommodate requested subnets");let[d,m,p,g]=n.split(".").map(Number),h=(d<<24)+(m<<16)+(p<<8)+g,y=2**(32-u),f=[];for(let b=0;b<a*r;b++){let
|
|
615
|
+
`,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class L{static createVpc(e){let{slug:a,environment:r,cidr:n="10.0.0.0/16",enableDnsHostnames:i=!0,enableDnsSupport:o=!0}=e,c=l({slug:a,environment:r,resourceType:"vpc"}),u=s(c);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:n,EnableDnsHostnames:i,EnableDnsSupport:o,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}},logicalId:u}}static createSubnet(e){let{slug:a,environment:r,vpcId:n,type:i,cidr:o,availabilityZone:c,mapPublicIp:u=i==="public"}=e,d=l({slug:a,environment:r,resourceType:`subnet-${i}`}),m=s(`${d}-${c}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:n,CidrBlock:o,AvailabilityZone:c,MapPublicIpOnLaunch:u,Tags:[{Key:"Name",Value:`${d}-${c}`},{Key:"Environment",Value:r},{Key:"Type",Value:i}]}},logicalId:m}}static createInternetGateway(e,a){let r=l({slug:e,environment:a,resourceType:"igw"}),n=s(r);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:a}]}},logicalId:n}}static attachInternetGateway(e,a){let r=s(`${e}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:P.Ref(e),InternetGatewayId:P.Ref(a)}},logicalId:r}}static createEip(e,a){let r=l({slug:e,environment:a,resourceType:"eip"}),n=s(r);return{eip:{Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:a}]}},logicalId:n}}static createNatGateway(e,a){let{slug:r,environment:n,subnetId:i}=e,o=l({slug:r,environment:n,resourceType:"nat"}),c=s(o);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:P.GetAtt(a,"AllocationId"),SubnetId:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:c}}static createRouteTable(e,a,r,n){let i=l({slug:e,environment:a,resourceType:`rt-${n}`}),o=s(i);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:P.Ref(r),Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:a},{Key:"Type",Value:n}]}},logicalId:o}}static createRoute(e,a,r){let n=s(`${e}-route-${r.type}`),i={Type:"AWS::EC2::Route",Properties:{RouteTableId:P.Ref(e),DestinationCidrBlock:a}};if(r.type==="igw")i.Properties.GatewayId=P.Ref(r.logicalId);else if(r.type==="nat")i.Properties.NatGatewayId=P.Ref(r.logicalId);else if(r.type==="instance")i.Properties.InstanceId=P.Ref(r.logicalId);return{route:i,logicalId:n}}static associateSubnetWithRouteTable(e,a){let r=s(`${e}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:P.Ref(e),RouteTableId:P.Ref(a)}},logicalId:r}}static enableFlowLogs(e){let{slug:a,environment:r,resourceId:n,resourceType:i,trafficType:o="ALL",logGroupName:c}=e,u=l({slug:a,environment:r,resourceType:"flowlog"}),d=s(u);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:i,ResourceIds:[n],TrafficType:o,LogDestinationType:"cloud-watch-logs",LogGroupName:c||`/aws/vpc/${a}-${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static calculateSubnetCidrs(e,a,r=3){let[n,i]=e.split("/"),o=Number.parseInt(i,10),c=Math.ceil(Math.log2(a*r)),u=o+c;if(u>28)throw Error("VPC CIDR is too small to accommodate requested subnets");let[d,m,p,g]=n.split(".").map(Number),h=(d<<24)+(m<<16)+(p<<8)+g,y=2**(32-u),f=[];for(let b=0;b<a*r;b++){let v=h+b*y,T=[v>>>24&255,v>>>16&255,v>>>8&255,v&255].join(".");f.push(`${T}/${u}`)}return f}static getAvailabilityZones(e,a){return["a","b","c","d","e","f"].slice(0,a).map((r)=>`${e}${r}`)}static createMultiAzNetwork(e){let{slug:a,environment:r,region:n,cidr:i="10.0.0.0/16",zones:o=3,enableNatGateway:c=!1,singleNatGateway:u=!1,enableFlowLogs:d=!1}=e,m={},p=[],g=[],h=[],{vpc:y,logicalId:f}=L.createVpc({slug:a,environment:r,cidr:i});m[f]=y;let{internetGateway:b,logicalId:v}=L.createInternetGateway(a,r);m[v]=b;let{attachment:T,logicalId:I}=L.attachInternetGateway(f,v);m[I]=T;let{routeTable:C,logicalId:N}=L.createRouteTable(a,r,f,"public");m[N]=C;let{route:R,logicalId:k}=L.createRoute(N,"0.0.0.0/0",{type:"igw",logicalId:v});R.DependsOn=I,m[k]=R;let x=L.calculateSubnetCidrs(i,o,2),M=L.getAvailabilityZones(n,o),B=[];for(let _=0;_<o;_++){let U=M[_],Y=x[_*2],q=x[_*2+1],{subnet:Q,logicalId:V}=L.createSubnet({slug:a,environment:r,vpcId:P.Ref(f),type:"public",cidr:Y,availabilityZone:U});m[V]=Q,p.push(V);let{association:me,logicalId:Me}=L.associateSubnetWithRouteTable(V,N);m[Me]=me;let{subnet:vt,logicalId:Z}=L.createSubnet({slug:a,environment:r,vpcId:P.Ref(f),type:"private",cidr:q,availabilityZone:U});if(m[Z]=vt,g.push(Z),c&&(!u||_===0)){let{eip:J,logicalId:ee}=L.createEip(`${a}-${U}`,r);m[ee]=J;let{natGateway:pe,logicalId:te}=L.createNatGateway({slug:`${a}-${U}`,environment:r,subnetId:P.Ref(V)},ee);pe.DependsOn=I,m[te]=pe,h.push(te);let{routeTable:oe,logicalId:Se}=L.createRouteTable(`${a}-${U}`,r,f,"private");m[Se]=oe,B.push(Se);let{route:Oe,logicalId:O}=L.createRoute(Se,"0.0.0.0/0",{type:"nat",logicalId:te});m[O]=Oe;let{association:G,logicalId:W}=L.associateSubnetWithRouteTable(Z,Se);m[W]=G}else if(c&&u&&_>0){let{association:J,logicalId:ee}=L.associateSubnetWithRouteTable(Z,B[0]);m[ee]=J}else{let{routeTable:J,logicalId:ee}=L.createRouteTable(`${a}-${U}-isolated`,r,f,"private");m[ee]=J;let{association:pe,logicalId:te}=L.associateSubnetWithRouteTable(Z,ee);m[te]=pe}}if(d){let{flowLog:_,logicalId:U}=L.enableFlowLogs({slug:a,environment:r,resourceId:P.Ref(f),resourceType:"VPC"});m[U]=_}return{resources:m,outputs:{vpcId:f,publicSubnetIds:p,privateSubnetIds:g,natGatewayIds:h.length>0?h: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 tt{static createFileSystem(e){let{slug:a,environment:r,encrypted:n=!0,kmsKeyId:i,performanceMode:o="generalPurpose",throughputMode:c="bursting",provisionedThroughput:u,enableBackup:d=!0}=e,m=l({slug:a,environment:r,resourceType:"efs"}),p=s(m),g={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:n,PerformanceMode:o,ThroughputMode:c,FileSystemTags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(i)g.Properties.KmsKeyId=i;if(c==="provisioned"&&u)g.Properties.ProvisionedThroughputInMibps=u;if(d)g.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:g,logicalId:p}}static createMountTarget(e,a){let{slug:r,environment:n,subnetId:i,securityGroups:o,ipAddress:c}=a,u=l({slug:r,environment:n,resourceType:"efs-mt"}),d=s(`${u}-${i}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:P.Ref(e),SubnetId:i,SecurityGroups:o}};if(c)m.Properties.IpAddress=c;return{mountTarget:m,logicalId:d}}static createAccessPoint(e,a){let{slug:r,environment:n,path:i="/",uid:o="1000",gid:c="1000",permissions:u="755"}=a,d=l({slug:r,environment:n,resourceType:"efs-ap"}),m=s(`${d}-${i.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:P.Ref(e),PosixUser:{Uid:o,Gid:c},RootDirectory:{Path:i,CreationInfo:{OwnerUid:o,OwnerGid:c,Permissions:u}},AccessPointTags:[{Key:"Name",Value:`${d}-${i}`},{Key:"Environment",Value:n}]}},logicalId:m}}static setLifecyclePolicy(e,a){let{transitionToIA:r,transitionToPrimary:n=!1}=a;if(!e.Properties)e.Properties={};if(e.Properties.LifecyclePolicies=[],r){let i=`AFTER_${r}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:i})}if(n)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,a){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="provisioned",e.Properties.ProvisionedThroughputInMibps=a,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:a,environment:r,vpcId:n,sourceSecurityGroupIds:i=[],sourceCidrBlocks:o=[],description:c}=e,u=l({slug:a,environment:r,resourceType:"efs-sg"}),d=s(u),m=[];for(let p of i)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:p,Description:"NFS from security group"});for(let p of o)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:p,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:u,GroupDescription:c||`Security group for EFS mount targets - ${a} ${r}`,VpcId:n,SecurityGroupIngress:m,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static createMultiAzMountTargets(e,a){let{slug:r,environment:n,subnetIds:i,securityGroupId:o}=a,c=[],u=[];for(let d=0;d<i.length;d++){let m=i[d],p=l({slug:r,environment:n,resourceType:"efs-mt"}),g=s(`${p}-az${d+1}`),h={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:P.Ref(e),SubnetId:m,SecurityGroups:[o]}};c.push(h),u.push(g)}return{mountTargets:c,logicalIds:u}}static createCompleteFileSystem(e){let{slug:a,environment:r,vpcId:n,subnetIds:i,sourceSecurityGroupIds:o=[],encrypted:c=!0,performanceMode:u="generalPurpose",throughputMode:d="elastic",enableBackup:m=!0,transitionToIA:p}=e,g={},{fileSystem:h,logicalId:y}=tt.createFileSystem({slug:a,environment:r,encrypted:c,performanceMode:u,throughputMode:d,enableBackup:m});if(p)tt.setLifecyclePolicy(h,{transitionToIA:p,transitionToPrimary:!0});g[y]=h;let{securityGroup:f,logicalId:b}=tt.createEfsSecurityGroup({slug:a,environment:r,vpcId:n,sourceSecurityGroupIds:o});g[b]=f;let{mountTargets:T,logicalIds:w}=tt.createMultiAzMountTargets(y,{slug:a,environment:r,subnetIds:i,securityGroupId:P.Ref(b)});for(let I=0;I<T.length;I++)g[w[I]]=T[I];return{resources:g,outputs:{fileSystemId:y,securityGroupId:b,mountTargetIds:w}}}}class D{static verifyDomain(e){let{domain:a,slug:r,environment:n,enableDkim:i=!0,dkimKeyLength:o="RSA_2048_BIT"}=e,c=l({slug:r,environment:n,resourceType:"ses-identity"}),u=s(`${c}-${a.replace(/\./g,"")}`),d={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:a,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(i)d.Properties.DkimSigningAttributes={NextSigningKeyLength:o};return{emailIdentity:d,logicalId:u}}static createDkimRecords(e,a,r){let n=[];for(let i=0;i<a.length;i++){let o=a[i],c=s(`dkim-${e.replace(/\./g,"")}-${i+1}`),u={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`${o}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${o}.dkim.amazonses.com`]}};n.push({record:u,logicalId:c})}return n}static createConfigurationSet(e){let{slug:a,environment:r,name:n,reputationMetrics:i=!0,sendingEnabled:o=!0,suppressBounces:c=!0,suppressComplaints:u=!0}=e,d=n||l({slug:a,environment:r,resourceType:"ses-config"}),m=s(d),p=[];if(c)p.push("BOUNCE");if(u)p.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:d,ReputationOptions:{ReputationMetricsEnabled:i},SendingOptions:{SendingEnabled:o},SuppressionOptions:{SuppressedReasons:p}}},logicalId:m}}static createReceiptRuleSet(e){let{slug:a,environment:r,name:n}=e,i=n||l({slug:a,environment:r,resourceType:"ses-ruleset"}),o=s(i);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:i}},logicalId:o}}static createReceiptRule(e,a){let{slug:r,environment:n,ruleSetName:i,recipients:o,enabled:c=!0,scanEnabled:u=!0,tlsPolicy:d="Require",s3Action:m,lambdaAction:p,snsAction:g}=a,h=l({slug:r,environment:n,resourceType:"ses-rule"}),y=s(h),f=[];if(m)f.push({S3Action:{BucketName:m.bucketName,ObjectKeyPrefix:m.prefix,KmsKeyArn:m.kmsKeyArn}});if(p)f.push({LambdaAction:{FunctionArn:p.functionArn,InvocationType:p.invocationType||"Event"}});if(g)f.push({SNSAction:{TopicArn:g.topicArn,Encoding:g.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:i,Rule:{Name:h,Enabled:c,ScanEnabled:u,TlsPolicy:d,Recipients:o,Actions:f.length>0?f:void 0}}},logicalId:y}}static createMxRecord(e,a,r){let n=s(`mx-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:e,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${r}.amazonaws.com`]}},logicalId:n}}static createVerificationRecord(e,a,r){let n=s(`verification-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`_amazonses.${e}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${a}"`]}},logicalId:n}}static getSmtpEndpoint(e){return`email-smtp.${e}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(e,a,r){let{includeDomains:n=[],softFail:i=!1}=r||{},o=s(`spf-${e.replace(/\./g,"")}`),c="v=spf1 include:amazonses.com";for(let u of n)c+=` include:${u}`;return c+=i?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${c}"`]}},logicalId:o}}static createDmarcRecord(e,a,r){let{policy:n="none",subdomainPolicy:i,percentage:o=100,reportingEmail:c,forensicEmail:u}=r||{},d=s(`dmarc-${e.replace(/\./g,"")}`),m=`v=DMARC1; p=${n}; pct=${o}`;if(i)m+=`; sp=${i}`;if(c)m+=`; rua=mailto:${c}`;if(u)m+=`; ruf=mailto:${u}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:`_dmarc.${e}`,Type:"TXT",TTL:300,ResourceRecords:[`"${m}"`]}},logicalId:d}}static createInboundEmailSetup(e){let{slug:a,environment:r,domain:n,s3BucketName:i,s3KeyPrefix:o="inbound/",region:c,hostedZoneId:u,lambdaFunctionArn:d,snsTopicArn:m}=e,p={},{ruleSet:g,logicalId:h}=D.createReceiptRuleSet({slug:a,environment:r});p[h]=g;let{receiptRule:y,logicalId:f}=D.createReceiptRule(h,{slug:a,environment:r,ruleSetName:g.Properties.RuleSetName||`${a}-${r}-receipt-rule-set`,recipients:[n],s3Action:{bucketName:i,prefix:o},lambdaAction:d?{functionArn:d,invocationType:"Event"}:void 0,snsAction:m?{topicArn:m}:void 0});p[f]=y;let{record:b,logicalId:T}=D.createMxRecord(n,u,c);return p[T]=b,{resources:p,outputs:{ruleSetLogicalId:h,ruleLogicalId:f,mxRecordLogicalId:T}}}static createCompleteDomainSetup(e){let{slug:a,environment:r,domain:n,hostedZoneId:i,region:o,enableInbound:c=!1,inboundS3Bucket:u,dmarcReportingEmail:d}=e,m={},{emailIdentity:p,logicalId:g}=D.verifyDomain({domain:n,slug:a,environment:r});m[g]=p;let{configurationSet:h,logicalId:y}=D.createConfigurationSet({slug:a,environment:r});m[y]=h;let{record:f,logicalId:b}=D.createSpfRecord(n,i);m[b]=f;let{record:T,logicalId:w}=D.createDmarcRecord(n,i,{policy:"none",reportingEmail:d||`dmarc-reports@${n}`});if(m[w]=T,c&&u){let I=D.createInboundEmailSetup({slug:a,environment:r,domain:n,s3BucketName:u,region:o,hostedZoneId:i});Object.assign(m,I.resources)}return{resources:m,outputs:{identityLogicalId:g,configSetLogicalId:y}}}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 D.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:a,environment:r,s3BucketArn:n,sesIdentityArn:i}=e,o=l({slug:a,environment:r,resourceType:"email-lambda-role"}),c=s(o),u=s(`${o}-policy`),d={Type:"AWS::IAM::Role",Properties:{RoleName:o,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:o},{Key:"Environment",Value:r}]}},m=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[n,`${n}/*`]}];if(i)m.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:i});let p={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${o}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:m},Roles:[P.Ref(c)]}};return{role:d,policy:p,roleLogicalId:c,policyLogicalId:u}}static createOutboundEmailLambda(e){let{slug:a,environment:r,roleArn:n,domain:i,configurationSetName:o,timeout:c=30,memorySize:u=256}=e,d=l({slug:a,environment:r,resourceType:"outbound-email"}),m=s(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:c,MemorySize:u,Environment:{Variables:{DOMAIN:i,CONFIGURATION_SET:o||""}},Code:{ZipFile:D.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:m}}static createInboundEmailLambda(e){let{slug:a,environment:r,roleArn:n,s3BucketName:i,organizedPrefix:o="organized/",timeout:c=60,memorySize:u=512}=e,d=l({slug:a,environment:r,resourceType:"inbound-email"}),m=s(d),p=s(`${d}-permission`),g={Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:i,ORGANIZED_PREFIX:o}},Code:{ZipFile:D.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"InboundEmail"}]}},h={Type:"AWS::Lambda::Permission",Properties:{FunctionName:P.Ref(m),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:P.Ref("AWS::AccountId")}};return{function:g,permission:h,logicalId:m,permissionLogicalId:p}}static createEmailConversionLambda(e){let{slug:a,environment:r,roleArn:n,s3BucketName:i,convertedPrefix:o="converted/",timeout:c=60,memorySize:u=512}=e,d=l({slug:a,environment:r,resourceType:"email-conversion"}),m=s(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:i,CONVERTED_PREFIX:o}},Code:{ZipFile:D.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:m}}static createEmailBucketNotification(e){let{lambdaArn:a,prefix:r="inbound/",suffix:n,events:i}=e,o=i??["s3:ObjectCreated:*"],c={};if(r||n){if(c.S3Key={Rules:[]},r)c.S3Key.Rules.push({Name:"prefix",Value:r});if(n)c.S3Key.Rules.push({Name:"suffix",Value:n})}return{notificationConfiguration:{LambdaConfigurations:[{Event:o[0],Function:a,Filter:Object.keys(c).length>0?c:void 0}]}}}static createS3LambdaPermission(e){let{slug:a,environment:r,lambdaLogicalId:n,s3BucketArn:i}=e,o=l({slug:a,environment:r,resourceType:"s3-lambda-permission"}),c=s(o);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:P.Ref(n),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:i}},logicalId:c}}static createEmailProcessingStack(e){let{slug:a,environment:r,domain:n,s3BucketName:i,s3BucketArn:o,configurationSetName:c,enableInbound:u=!0,enableConversion:d=!0}=e,m={},{role:p,policy:g,roleLogicalId:h,policyLogicalId:y}=D.createEmailLambdaRole({slug:a,environment:r,s3BucketArn:o,sesIdentityArn:`arn:aws:ses:*:*:identity/${n}`});m[h]=p,m[y]=g;let{function:f,logicalId:b}=D.createOutboundEmailLambda({slug:a,environment:r,roleArn:P.GetAtt(h,"Arn"),domain:n,configurationSetName:c});m[b]=f;let T={roleLogicalId:h,outboundLambdaLogicalId:b};if(u){let{function:w,permission:I,logicalId:v,permissionLogicalId:N}=D.createInboundEmailLambda({slug:a,environment:r,roleArn:P.GetAtt(h,"Arn"),s3BucketName:i});m[v]=w,m[N]=I;let{permission:R,logicalId:k}=D.createS3LambdaPermission({slug:a,environment:r,lambdaLogicalId:v,s3BucketArn:o});m[k]=R,T.inboundLambdaLogicalId=v}if(d){let{function:w,logicalId:I}=D.createEmailConversionLambda({slug:a,environment:r,roleArn:P.GetAtt(h,"Arn"),s3BucketName:i});m[I]=w,T.conversionLambdaLogicalId=I}return{resources:m,outputs:T}}static LambdaCode={outboundEmail:`
|
|
623
|
+
`}class tt{static createFileSystem(e){let{slug:a,environment:r,encrypted:n=!0,kmsKeyId:i,performanceMode:o="generalPurpose",throughputMode:c="bursting",provisionedThroughput:u,enableBackup:d=!0}=e,m=l({slug:a,environment:r,resourceType:"efs"}),p=s(m),g={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:n,PerformanceMode:o,ThroughputMode:c,FileSystemTags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(i)g.Properties.KmsKeyId=i;if(c==="provisioned"&&u)g.Properties.ProvisionedThroughputInMibps=u;if(d)g.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:g,logicalId:p}}static createMountTarget(e,a){let{slug:r,environment:n,subnetId:i,securityGroups:o,ipAddress:c}=a,u=l({slug:r,environment:n,resourceType:"efs-mt"}),d=s(`${u}-${i}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:P.Ref(e),SubnetId:i,SecurityGroups:o}};if(c)m.Properties.IpAddress=c;return{mountTarget:m,logicalId:d}}static createAccessPoint(e,a){let{slug:r,environment:n,path:i="/",uid:o="1000",gid:c="1000",permissions:u="755"}=a,d=l({slug:r,environment:n,resourceType:"efs-ap"}),m=s(`${d}-${i.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:P.Ref(e),PosixUser:{Uid:o,Gid:c},RootDirectory:{Path:i,CreationInfo:{OwnerUid:o,OwnerGid:c,Permissions:u}},AccessPointTags:[{Key:"Name",Value:`${d}-${i}`},{Key:"Environment",Value:n}]}},logicalId:m}}static setLifecyclePolicy(e,a){let{transitionToIA:r,transitionToPrimary:n=!1}=a;if(!e.Properties)e.Properties={};if(e.Properties.LifecyclePolicies=[],r){let i=`AFTER_${r}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:i})}if(n)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,a){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="provisioned",e.Properties.ProvisionedThroughputInMibps=a,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:a,environment:r,vpcId:n,sourceSecurityGroupIds:i=[],sourceCidrBlocks:o=[],description:c}=e,u=l({slug:a,environment:r,resourceType:"efs-sg"}),d=s(u),m=[];for(let p of i)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:p,Description:"NFS from security group"});for(let p of o)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:p,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:u,GroupDescription:c||`Security group for EFS mount targets - ${a} ${r}`,VpcId:n,SecurityGroupIngress:m,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static createMultiAzMountTargets(e,a){let{slug:r,environment:n,subnetIds:i,securityGroupId:o}=a,c=[],u=[];for(let d=0;d<i.length;d++){let m=i[d],p=l({slug:r,environment:n,resourceType:"efs-mt"}),g=s(`${p}-az${d+1}`),h={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:P.Ref(e),SubnetId:m,SecurityGroups:[o]}};c.push(h),u.push(g)}return{mountTargets:c,logicalIds:u}}static createCompleteFileSystem(e){let{slug:a,environment:r,vpcId:n,subnetIds:i,sourceSecurityGroupIds:o=[],encrypted:c=!0,performanceMode:u="generalPurpose",throughputMode:d="elastic",enableBackup:m=!0,transitionToIA:p}=e,g={},{fileSystem:h,logicalId:y}=tt.createFileSystem({slug:a,environment:r,encrypted:c,performanceMode:u,throughputMode:d,enableBackup:m});if(p)tt.setLifecyclePolicy(h,{transitionToIA:p,transitionToPrimary:!0});g[y]=h;let{securityGroup:f,logicalId:b}=tt.createEfsSecurityGroup({slug:a,environment:r,vpcId:n,sourceSecurityGroupIds:o});g[b]=f;let{mountTargets:v,logicalIds:T}=tt.createMultiAzMountTargets(y,{slug:a,environment:r,subnetIds:i,securityGroupId:P.Ref(b)});for(let I=0;I<v.length;I++)g[T[I]]=v[I];return{resources:g,outputs:{fileSystemId:y,securityGroupId:b,mountTargetIds:T}}}}class D{static verifyDomain(e){let{domain:a,slug:r,environment:n,enableDkim:i=!0,dkimKeyLength:o="RSA_2048_BIT"}=e,c=l({slug:r,environment:n,resourceType:"ses-identity"}),u=s(`${c}-${a.replace(/\./g,"")}`),d={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:a,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(i)d.Properties.DkimSigningAttributes={NextSigningKeyLength:o};return{emailIdentity:d,logicalId:u}}static createDkimRecords(e,a,r){let n=[];for(let i=0;i<a.length;i++){let o=a[i],c=s(`dkim-${e.replace(/\./g,"")}-${i+1}`),u={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`${o}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${o}.dkim.amazonses.com`]}};n.push({record:u,logicalId:c})}return n}static createConfigurationSet(e){let{slug:a,environment:r,name:n,reputationMetrics:i=!0,sendingEnabled:o=!0,suppressBounces:c=!0,suppressComplaints:u=!0}=e,d=n||l({slug:a,environment:r,resourceType:"ses-config"}),m=s(d),p=[];if(c)p.push("BOUNCE");if(u)p.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:d,ReputationOptions:{ReputationMetricsEnabled:i},SendingOptions:{SendingEnabled:o},SuppressionOptions:{SuppressedReasons:p}}},logicalId:m}}static createReceiptRuleSet(e){let{slug:a,environment:r,name:n}=e,i=n||l({slug:a,environment:r,resourceType:"ses-ruleset"}),o=s(i);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:i}},logicalId:o}}static createReceiptRule(e,a){let{slug:r,environment:n,ruleSetName:i,recipients:o,enabled:c=!0,scanEnabled:u=!0,tlsPolicy:d="Require",s3Action:m,lambdaAction:p,snsAction:g}=a,h=l({slug:r,environment:n,resourceType:"ses-rule"}),y=s(h),f=[];if(m)f.push({S3Action:{BucketName:m.bucketName,ObjectKeyPrefix:m.prefix,KmsKeyArn:m.kmsKeyArn}});if(p)f.push({LambdaAction:{FunctionArn:p.functionArn,InvocationType:p.invocationType||"Event"}});if(g)f.push({SNSAction:{TopicArn:g.topicArn,Encoding:g.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:i,Rule:{Name:h,Enabled:c,ScanEnabled:u,TlsPolicy:d,Recipients:o,Actions:f.length>0?f:void 0}}},logicalId:y}}static createMxRecord(e,a,r){let n=s(`mx-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:e,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${r}.amazonaws.com`]}},logicalId:n}}static createVerificationRecord(e,a,r){let n=s(`verification-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`_amazonses.${e}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${a}"`]}},logicalId:n}}static getSmtpEndpoint(e){return`email-smtp.${e}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(e,a,r){let{includeDomains:n=[],softFail:i=!1}=r||{},o=s(`spf-${e.replace(/\./g,"")}`),c="v=spf1 include:amazonses.com";for(let u of n)c+=` include:${u}`;return c+=i?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${c}"`]}},logicalId:o}}static createDmarcRecord(e,a,r){let{policy:n="none",subdomainPolicy:i,percentage:o=100,reportingEmail:c,forensicEmail:u}=r||{},d=s(`dmarc-${e.replace(/\./g,"")}`),m=`v=DMARC1; p=${n}; pct=${o}`;if(i)m+=`; sp=${i}`;if(c)m+=`; rua=mailto:${c}`;if(u)m+=`; ruf=mailto:${u}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:`_dmarc.${e}`,Type:"TXT",TTL:300,ResourceRecords:[`"${m}"`]}},logicalId:d}}static createInboundEmailSetup(e){let{slug:a,environment:r,domain:n,s3BucketName:i,s3KeyPrefix:o="inbound/",region:c,hostedZoneId:u,lambdaFunctionArn:d,snsTopicArn:m}=e,p={},{ruleSet:g,logicalId:h}=D.createReceiptRuleSet({slug:a,environment:r});p[h]=g;let{receiptRule:y,logicalId:f}=D.createReceiptRule(h,{slug:a,environment:r,ruleSetName:g.Properties.RuleSetName||`${a}-${r}-receipt-rule-set`,recipients:[n],s3Action:{bucketName:i,prefix:o},lambdaAction:d?{functionArn:d,invocationType:"Event"}:void 0,snsAction:m?{topicArn:m}:void 0});p[f]=y;let{record:b,logicalId:v}=D.createMxRecord(n,u,c);return p[v]=b,{resources:p,outputs:{ruleSetLogicalId:h,ruleLogicalId:f,mxRecordLogicalId:v}}}static createCompleteDomainSetup(e){let{slug:a,environment:r,domain:n,hostedZoneId:i,region:o,enableInbound:c=!1,inboundS3Bucket:u,dmarcReportingEmail:d}=e,m={},{emailIdentity:p,logicalId:g}=D.verifyDomain({domain:n,slug:a,environment:r});m[g]=p;let{configurationSet:h,logicalId:y}=D.createConfigurationSet({slug:a,environment:r});m[y]=h;let{record:f,logicalId:b}=D.createSpfRecord(n,i);m[b]=f;let{record:v,logicalId:T}=D.createDmarcRecord(n,i,{policy:"none",reportingEmail:d||`dmarc-reports@${n}`});if(m[T]=v,c&&u){let I=D.createInboundEmailSetup({slug:a,environment:r,domain:n,s3BucketName:u,region:o,hostedZoneId:i});Object.assign(m,I.resources)}return{resources:m,outputs:{identityLogicalId:g,configSetLogicalId:y}}}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 D.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:a,environment:r,s3BucketArn:n,sesIdentityArn:i}=e,o=l({slug:a,environment:r,resourceType:"email-lambda-role"}),c=s(o),u=s(`${o}-policy`),d={Type:"AWS::IAM::Role",Properties:{RoleName:o,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:o},{Key:"Environment",Value:r}]}},m=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[n,`${n}/*`]}];if(i)m.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:i});let p={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${o}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:m},Roles:[P.Ref(c)]}};return{role:d,policy:p,roleLogicalId:c,policyLogicalId:u}}static createOutboundEmailLambda(e){let{slug:a,environment:r,roleArn:n,domain:i,configurationSetName:o,timeout:c=30,memorySize:u=256}=e,d=l({slug:a,environment:r,resourceType:"outbound-email"}),m=s(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:c,MemorySize:u,Environment:{Variables:{DOMAIN:i,CONFIGURATION_SET:o||""}},Code:{ZipFile:D.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:m}}static createInboundEmailLambda(e){let{slug:a,environment:r,roleArn:n,s3BucketName:i,organizedPrefix:o="organized/",timeout:c=60,memorySize:u=512}=e,d=l({slug:a,environment:r,resourceType:"inbound-email"}),m=s(d),p=s(`${d}-permission`),g={Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:i,ORGANIZED_PREFIX:o}},Code:{ZipFile:D.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"InboundEmail"}]}},h={Type:"AWS::Lambda::Permission",Properties:{FunctionName:P.Ref(m),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:P.Ref("AWS::AccountId")}};return{function:g,permission:h,logicalId:m,permissionLogicalId:p}}static createEmailConversionLambda(e){let{slug:a,environment:r,roleArn:n,s3BucketName:i,convertedPrefix:o="converted/",timeout:c=60,memorySize:u=512}=e,d=l({slug:a,environment:r,resourceType:"email-conversion"}),m=s(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:i,CONVERTED_PREFIX:o}},Code:{ZipFile:D.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:m}}static createEmailBucketNotification(e){let{lambdaArn:a,prefix:r="inbound/",suffix:n,events:i}=e,o=i??["s3:ObjectCreated:*"],c={};if(r||n){if(c.S3Key={Rules:[]},r)c.S3Key.Rules.push({Name:"prefix",Value:r});if(n)c.S3Key.Rules.push({Name:"suffix",Value:n})}return{notificationConfiguration:{LambdaConfigurations:[{Event:o[0],Function:a,Filter:Object.keys(c).length>0?c:void 0}]}}}static createS3LambdaPermission(e){let{slug:a,environment:r,lambdaLogicalId:n,s3BucketArn:i}=e,o=l({slug:a,environment:r,resourceType:"s3-lambda-permission"}),c=s(o);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:P.Ref(n),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:i}},logicalId:c}}static createEmailProcessingStack(e){let{slug:a,environment:r,domain:n,s3BucketName:i,s3BucketArn:o,configurationSetName:c,enableInbound:u=!0,enableConversion:d=!0}=e,m={},{role:p,policy:g,roleLogicalId:h,policyLogicalId:y}=D.createEmailLambdaRole({slug:a,environment:r,s3BucketArn:o,sesIdentityArn:`arn:aws:ses:*:*:identity/${n}`});m[h]=p,m[y]=g;let{function:f,logicalId:b}=D.createOutboundEmailLambda({slug:a,environment:r,roleArn:P.GetAtt(h,"Arn"),domain:n,configurationSetName:c});m[b]=f;let v={roleLogicalId:h,outboundLambdaLogicalId:b};if(u){let{function:T,permission:I,logicalId:C,permissionLogicalId:N}=D.createInboundEmailLambda({slug:a,environment:r,roleArn:P.GetAtt(h,"Arn"),s3BucketName:i});m[C]=T,m[N]=I;let{permission:R,logicalId:k}=D.createS3LambdaPermission({slug:a,environment:r,lambdaLogicalId:C,s3BucketArn:o});m[k]=R,v.inboundLambdaLogicalId=C}if(d){let{function:T,logicalId:I}=D.createEmailConversionLambda({slug:a,environment:r,roleArn:P.GetAtt(h,"Arn"),s3BucketName:i});m[I]=T,v.conversionLambdaLogicalId=I}return{resources:m,outputs:v}}static LambdaCode={outboundEmail:`
|
|
624
624
|
const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
|
|
625
625
|
const ses = new SESClient({});
|
|
626
626
|
|
|
@@ -1658,7 +1658,7 @@ catch (error) {
|
|
|
1658
1658
|
|
|
1659
1659
|
return { statusCode: 200, body: 'OK' };
|
|
1660
1660
|
};
|
|
1661
|
-
`;class wt{static LambdaCode={incomingCall:er,voicemail:tn,missedCall:en};static createConnectInstance(e){let{slug:a,environment:r,instanceAlias:n,inboundCallsEnabled:i=!0,outboundCallsEnabled:o=!0}=e;return{[`${a}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:n,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:i,OutboundCalls:o,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((a)=>({Day:a.day,StartTime:{Hours:a.startHour,Minutes:a.startMinute},EndTime:{Hours:a.endHour,Minutes:a.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 a={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(a)}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:wt.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:wt.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:wt.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 a={},r={};Object.assign(a,wt.createPhoneLambdaRole({slug:e.slug})),Object.assign(a,wt.createCallLogTable({slug:e.slug})),a[`${e.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-phone-notifications`}},a[`${e.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let n={"Fn::GetAtt":[`${e.slug}PhoneLambdaRole`,"Arn"]},i={Ref:`${e.slug}PhoneNotificationTopic`},o={Ref:`${e.slug}CallLogTable`},c={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(a,wt.createIncomingCallLambda({slug:e.slug,roleArn:n,notificationTopicArn:i,callLogTable:o,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(a,wt.createVoicemailLambda({slug:e.slug,roleArn:n,voicemailBucket:c,notificationTopicArn:i,callLogTable:o,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(a,wt.createMissedCallLambda({slug:e.slug,roleArn:n,notificationTopicArn:i,callLogTable:o,webhookUrl:e.webhookUrl})),r[`${e.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${e.slug}PhoneNotificationTopic`}},r[`${e.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${e.slug}CallLogTable`}},r[`${e.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${e.slug}VoicemailBucket`}},{resources:a,outputs:r}}}class ge{static createQueue(e){let{slug:a,environment:r,name:n,delaySeconds:i=0,visibilityTimeout:o=30,messageRetentionPeriod:c=345600,maxMessageSize:u=262144,receiveMessageWaitTime:d=0,fifo:m=!1,contentBasedDeduplication:p=!1,encrypted:g=!0,kmsKeyId:h}=e,y=n||l({slug:a,environment:r,resourceType:"queue"}),f=m?`${y}.fifo`:y,b=s(y),T={Type:"AWS::SQS::Queue",Properties:{QueueName:f,DelaySeconds:i,MaximumMessageSize:u,MessageRetentionPeriod:c,ReceiveMessageWaitTimeSeconds:d,VisibilityTimeout:o,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:r}]}};if(m)T.Properties.FifoQueue=!0,T.Properties.ContentBasedDeduplication=p;if(g)if(h)T.Properties.KmsMasterKeyId=h;else T.Properties.SqsManagedSseEnabled=!0;return{queue:T,logicalId:b}}static createDeadLetterQueue(e,a){let{slug:r,environment:n,maxReceiveCount:i=3}=a,o=l({slug:r,environment:n,resourceType:"dlq"}),c=s(o),u={Type:"AWS::SQS::Queue",Properties:{QueueName:o,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n},{Key:"Type",Value:"DeadLetterQueue"}]}},d={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:P.GetAtt(c,"Arn"),maxReceiveCount:i}}};return{deadLetterQueue:u,updatedSourceQueue:d,deadLetterLogicalId:c}}static createSchedule(e,a){let{slug:r,environment:n,name:i,description:o,enabled:c=!0}=a,u=i||l({slug:r,environment:n,resourceType:"schedule"}),d=s(u);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:u,Description:o,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[]}},logicalId:d}}static scheduleEcsTask(e,a,r){let{slug:n,environment:i,name:o,description:c,enabled:u=!0,taskDefinitionArn:d,clusterArn:m,subnets:p,securityGroups:g=[],assignPublicIp:h=!1,taskCount:y=1,containerOverrides:f}=r,b=o||l({slug:n,environment:i,resourceType:"ecs-schedule"}),T=s(b),w={Id:"1",Arn:m,RoleArn:a,EcsParameters:{TaskDefinitionArn:d,TaskCount:y,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:p,SecurityGroups:g,AssignPublicIp:h?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(f&&f.length>0)w.Input=JSON.stringify({containerOverrides:f});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:b,Description:c||`Scheduled ECS task: ${d}`,ScheduleExpression:e,State:u?"ENABLED":"DISABLED",Targets:[w]}},logicalId:T}}static scheduleLambda(e,a){let{slug:r,environment:n,name:i,description:o,enabled:c=!0,functionArn:u,input:d}=a,m=i||l({slug:r,environment:n,resourceType:"lambda-schedule"}),p=s(m),g={Id:"1",Arn:u};if(d)g.Input=JSON.stringify(d);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:o||`Scheduled Lambda: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static scheduleSqsMessage(e,a){let{slug:r,environment:n,name:i,description:o,enabled:c=!0,queueArn:u,messageGroupId:d}=a,m=i||l({slug:r,environment:n,resourceType:"sqs-schedule"}),p=s(m),g={Id:"1",Arn:u};if(d)g.SqsParameters={MessageGroupId:d};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:o||`Scheduled SQS message: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static addTarget(e,a){if(!e.Properties.Targets)e.Properties.Targets=[];let r={Id:a.id,Arn:a.arn};if(a.roleArn)r.RoleArn=a.roleArn;if(a.input)r.Input=JSON.stringify(a.input);return e.Properties.Targets.push(r),e}static toCronExpression(e){if(e.startsWith("cron(")||e.startsWith("rate("))return e;return`cron(${e})`}static rateExpression(e,a){return`rate(${e} ${a})`}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 a=e.toLowerCase().trim(),r=a.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(r){let m=parseInt(r[1],10),p=r[2].toLowerCase(),g=p.endsWith("s")&&m===1?p.slice(0,-1):p,h=!p.endsWith("s")&&m>1?`${p}s`:p;return`rate(${m} ${m===1?g:h})`}let n=a.match(/^every\s+(minute|hour|day)$/i);if(n)return`rate(1 ${n[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[a])return i[a];let o=a.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(o){let m=parseInt(o[1],10),p=o[2]?.toLowerCase();if(p==="pm"&&m!==12)m+=12;else if(p==="am"&&m===12)m=0;return`cron(0 ${m} * * ? *)`}let c=a.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(c){let m=parseInt(c[1],10);return`cron(${parseInt(c[2],10)} ${m} * * ? *)`}let u={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},d=a.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(d)return`cron(0 0 ? * ${u[d[1].toLowerCase()]} *)`;return ge.toCronExpression(e)}static JobConfig={create:(e)=>{let{name:a,handler:r,retries:n=3,backoff:i="exponential",backoffDelay:o=1000,maxDelay:c=30000,timeout:u=60000,jitter:d=!0}=e;return{name:a,handler:r,retries:n,backoff:i,backoffDelay:o,maxDelay:c,timeout:u,jitter:d}},calculateDelay:(e,a)=>{let{backoff:r,backoffDelay:n,maxDelay:i,jitter:o}=a,c;switch(r){case"linear":c=n*e;break;case"exponential":c=n*2**(e-1);break;case"fixed":default:c=n}if(c=Math.min(c,i||Number.MAX_SAFE_INTEGER),o){let u=c*0.25*Math.random();c+=u}return Math.floor(c)},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:a,jobClass:r,jobData:n,environment:i={}}=e,o=[{name:"JOB_CLASS",value:r}];if(n)o.push({name:"JOB_DATA",value:JSON.stringify(n)});for(let[c,u]of Object.entries(i))o.push({name:c,value:u});return{name:a,command:["bun","run","app/Jobs/runner.ts"],environment:o}}static createScheduledJob(e){let{slug:a,environment:r,schedule:n,jobClass:i,jobData:o,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m=[],roleArn:p,containerName:g="app"}=e,h=ge.rateStringToExpression(n),y=ge.createJobContainerOverride({containerName:g,jobClass:i,jobData:o});return ge.scheduleEcsTask(h,p,{slug:a,environment:r,name:`${a}-${i.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${i}`,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m,containerOverrides:[y]})}static QueuePresets={highThroughput:(e,a)=>ge.createQueue({slug:e,environment:a,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,a)=>ge.createQueue({slug:e,environment:a,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,a)=>ge.createQueue({slug:e,environment:a,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,a,r=60)=>ge.createQueue({slug:e,environment:a,delaySeconds:r})}}class Vt{static async discoverJobs(e){let{projectRoot:a,jobsPath:r="app/Jobs"}=e,n=`${a}/${r}`,i=[];try{let o=await import("node:fs"),c=await import("node:path");if(!o.existsSync(n))return[];let u=o.readdirSync(n).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_")&&d!=="runner.ts");for(let d of u){let m=c.join(n,d),p=d.replace(".ts",""),g=o.readFileSync(m,"utf-8"),h=Vt.parseJobMetadata(g,p,m);if(h)i.push(h)}}catch{return[]}return i}static parseJobMetadata(e,a,r){let n=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)/),o=e.match(/export\s+const\s+retries\s*=\s*(\d+)/)||e.match(/retries:\s*(\d+)/),c=e.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||e.match(/timeout:\s*(\d+)/),u=e.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||e.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),d=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:a,path:r,schedule:n?.[1],handler:`${a}.handle`,enabled:i?.[1]!=="false",retries:o?parseInt(o[1],10):void 0,backoff:u?.[1],timeout:c?parseInt(c[1],10):void 0,description:d?.[1]}}static async discoverActions(e){let{projectRoot:a,actionsPath:r="app/Actions"}=e,n=`${a}/${r}`,i=[];try{let o=await import("node:fs"),c=await import("node:path");if(!o.existsSync(n))return[];let u=o.readdirSync(n).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_"));for(let d of u){let m=c.join(n,d),p=d.replace(".ts",""),g=o.readFileSync(m,"utf-8"),h=Vt.parseActionMetadata(g,p,m);if(h)i.push(h)}}catch{return[]}return i}static parseActionMetadata(e,a,r){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let n=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:a,path:r,handler:`${a}.handle`,description:n?.[1]}}static generateScheduledJobResources(e){let{slug:a,environment:r,jobs:n,taskDefinitionArn:i,clusterArn:o,subnets:c,securityGroups:u=[],roleArn:d,containerName:m="app"}=e,p={},g=0;for(let h of n){if(!h.schedule||!h.enabled)continue;let{rule:y,logicalId:f}=ge.createScheduledJob({slug:a,environment:r,schedule:h.schedule,jobClass:h.name,taskDefinitionArn:i,clusterArn:o,subnets:c,securityGroups:u,roleArn:d,containerName:m});p[f]=y,g++}return{rules:p,count:g}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1661
|
+
`;class Ct{static LambdaCode={incomingCall:er,voicemail:tn,missedCall:en};static createConnectInstance(e){let{slug:a,environment:r,instanceAlias:n,inboundCallsEnabled:i=!0,outboundCallsEnabled:o=!0}=e;return{[`${a}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:n,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:i,OutboundCalls:o,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((a)=>({Day:a.day,StartTime:{Hours:a.startHour,Minutes:a.startMinute},EndTime:{Hours:a.endHour,Minutes:a.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 a={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(a)}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:Ct.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:Ct.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:Ct.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 a={},r={};Object.assign(a,Ct.createPhoneLambdaRole({slug:e.slug})),Object.assign(a,Ct.createCallLogTable({slug:e.slug})),a[`${e.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-phone-notifications`}},a[`${e.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let n={"Fn::GetAtt":[`${e.slug}PhoneLambdaRole`,"Arn"]},i={Ref:`${e.slug}PhoneNotificationTopic`},o={Ref:`${e.slug}CallLogTable`},c={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(a,Ct.createIncomingCallLambda({slug:e.slug,roleArn:n,notificationTopicArn:i,callLogTable:o,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(a,Ct.createVoicemailLambda({slug:e.slug,roleArn:n,voicemailBucket:c,notificationTopicArn:i,callLogTable:o,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(a,Ct.createMissedCallLambda({slug:e.slug,roleArn:n,notificationTopicArn:i,callLogTable:o,webhookUrl:e.webhookUrl})),r[`${e.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${e.slug}PhoneNotificationTopic`}},r[`${e.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${e.slug}CallLogTable`}},r[`${e.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${e.slug}VoicemailBucket`}},{resources:a,outputs:r}}}class ge{static createQueue(e){let{slug:a,environment:r,name:n,delaySeconds:i=0,visibilityTimeout:o=30,messageRetentionPeriod:c=345600,maxMessageSize:u=262144,receiveMessageWaitTime:d=0,fifo:m=!1,contentBasedDeduplication:p=!1,encrypted:g=!0,kmsKeyId:h}=e,y=n||l({slug:a,environment:r,resourceType:"queue"}),f=m?`${y}.fifo`:y,b=s(y),v={Type:"AWS::SQS::Queue",Properties:{QueueName:f,DelaySeconds:i,MaximumMessageSize:u,MessageRetentionPeriod:c,ReceiveMessageWaitTimeSeconds:d,VisibilityTimeout:o,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:r}]}};if(m)v.Properties.FifoQueue=!0,v.Properties.ContentBasedDeduplication=p;if(g)if(h)v.Properties.KmsMasterKeyId=h;else v.Properties.SqsManagedSseEnabled=!0;return{queue:v,logicalId:b}}static createDeadLetterQueue(e,a){let{slug:r,environment:n,maxReceiveCount:i=3}=a,o=l({slug:r,environment:n,resourceType:"dlq"}),c=s(o),u={Type:"AWS::SQS::Queue",Properties:{QueueName:o,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n},{Key:"Type",Value:"DeadLetterQueue"}]}},d={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:P.GetAtt(c,"Arn"),maxReceiveCount:i}}};return{deadLetterQueue:u,updatedSourceQueue:d,deadLetterLogicalId:c}}static createSchedule(e,a){let{slug:r,environment:n,name:i,description:o,enabled:c=!0}=a,u=i||l({slug:r,environment:n,resourceType:"schedule"}),d=s(u);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:u,Description:o,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[]}},logicalId:d}}static scheduleEcsTask(e,a,r){let{slug:n,environment:i,name:o,description:c,enabled:u=!0,taskDefinitionArn:d,clusterArn:m,subnets:p,securityGroups:g=[],assignPublicIp:h=!1,taskCount:y=1,containerOverrides:f}=r,b=o||l({slug:n,environment:i,resourceType:"ecs-schedule"}),v=s(b),T={Id:"1",Arn:m,RoleArn:a,EcsParameters:{TaskDefinitionArn:d,TaskCount:y,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:p,SecurityGroups:g,AssignPublicIp:h?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(f&&f.length>0)T.Input=JSON.stringify({containerOverrides:f});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:b,Description:c||`Scheduled ECS task: ${d}`,ScheduleExpression:e,State:u?"ENABLED":"DISABLED",Targets:[T]}},logicalId:v}}static scheduleLambda(e,a){let{slug:r,environment:n,name:i,description:o,enabled:c=!0,functionArn:u,input:d}=a,m=i||l({slug:r,environment:n,resourceType:"lambda-schedule"}),p=s(m),g={Id:"1",Arn:u};if(d)g.Input=JSON.stringify(d);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:o||`Scheduled Lambda: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static scheduleSqsMessage(e,a){let{slug:r,environment:n,name:i,description:o,enabled:c=!0,queueArn:u,messageGroupId:d}=a,m=i||l({slug:r,environment:n,resourceType:"sqs-schedule"}),p=s(m),g={Id:"1",Arn:u};if(d)g.SqsParameters={MessageGroupId:d};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:o||`Scheduled SQS message: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static addTarget(e,a){if(!e.Properties.Targets)e.Properties.Targets=[];let r={Id:a.id,Arn:a.arn};if(a.roleArn)r.RoleArn=a.roleArn;if(a.input)r.Input=JSON.stringify(a.input);return e.Properties.Targets.push(r),e}static toCronExpression(e){if(e.startsWith("cron(")||e.startsWith("rate("))return e;return`cron(${e})`}static rateExpression(e,a){return`rate(${e} ${a})`}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 a=e.toLowerCase().trim(),r=a.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(r){let m=parseInt(r[1],10),p=r[2].toLowerCase(),g=p.endsWith("s")&&m===1?p.slice(0,-1):p,h=!p.endsWith("s")&&m>1?`${p}s`:p;return`rate(${m} ${m===1?g:h})`}let n=a.match(/^every\s+(minute|hour|day)$/i);if(n)return`rate(1 ${n[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[a])return i[a];let o=a.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(o){let m=parseInt(o[1],10),p=o[2]?.toLowerCase();if(p==="pm"&&m!==12)m+=12;else if(p==="am"&&m===12)m=0;return`cron(0 ${m} * * ? *)`}let c=a.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(c){let m=parseInt(c[1],10);return`cron(${parseInt(c[2],10)} ${m} * * ? *)`}let u={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},d=a.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(d)return`cron(0 0 ? * ${u[d[1].toLowerCase()]} *)`;return ge.toCronExpression(e)}static JobConfig={create:(e)=>{let{name:a,handler:r,retries:n=3,backoff:i="exponential",backoffDelay:o=1000,maxDelay:c=30000,timeout:u=60000,jitter:d=!0}=e;return{name:a,handler:r,retries:n,backoff:i,backoffDelay:o,maxDelay:c,timeout:u,jitter:d}},calculateDelay:(e,a)=>{let{backoff:r,backoffDelay:n,maxDelay:i,jitter:o}=a,c;switch(r){case"linear":c=n*e;break;case"exponential":c=n*2**(e-1);break;case"fixed":default:c=n}if(c=Math.min(c,i||Number.MAX_SAFE_INTEGER),o){let u=c*0.25*Math.random();c+=u}return Math.floor(c)},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:a,jobClass:r,jobData:n,environment:i={}}=e,o=[{name:"JOB_CLASS",value:r}];if(n)o.push({name:"JOB_DATA",value:JSON.stringify(n)});for(let[c,u]of Object.entries(i))o.push({name:c,value:u});return{name:a,command:["bun","run","app/Jobs/runner.ts"],environment:o}}static createScheduledJob(e){let{slug:a,environment:r,schedule:n,jobClass:i,jobData:o,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m=[],roleArn:p,containerName:g="app"}=e,h=ge.rateStringToExpression(n),y=ge.createJobContainerOverride({containerName:g,jobClass:i,jobData:o});return ge.scheduleEcsTask(h,p,{slug:a,environment:r,name:`${a}-${i.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${i}`,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m,containerOverrides:[y]})}static QueuePresets={highThroughput:(e,a)=>ge.createQueue({slug:e,environment:a,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,a)=>ge.createQueue({slug:e,environment:a,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,a)=>ge.createQueue({slug:e,environment:a,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,a,r=60)=>ge.createQueue({slug:e,environment:a,delaySeconds:r})}}class Vt{static async discoverJobs(e){let{projectRoot:a,jobsPath:r="app/Jobs"}=e,n=`${a}/${r}`,i=[];try{let o=await import("node:fs"),c=await import("node:path");if(!o.existsSync(n))return[];let u=o.readdirSync(n).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_")&&d!=="runner.ts");for(let d of u){let m=c.join(n,d),p=d.replace(".ts",""),g=o.readFileSync(m,"utf-8"),h=Vt.parseJobMetadata(g,p,m);if(h)i.push(h)}}catch{return[]}return i}static parseJobMetadata(e,a,r){let n=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)/),o=e.match(/export\s+const\s+retries\s*=\s*(\d+)/)||e.match(/retries:\s*(\d+)/),c=e.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||e.match(/timeout:\s*(\d+)/),u=e.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||e.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),d=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:a,path:r,schedule:n?.[1],handler:`${a}.handle`,enabled:i?.[1]!=="false",retries:o?parseInt(o[1],10):void 0,backoff:u?.[1],timeout:c?parseInt(c[1],10):void 0,description:d?.[1]}}static async discoverActions(e){let{projectRoot:a,actionsPath:r="app/Actions"}=e,n=`${a}/${r}`,i=[];try{let o=await import("node:fs"),c=await import("node:path");if(!o.existsSync(n))return[];let u=o.readdirSync(n).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_"));for(let d of u){let m=c.join(n,d),p=d.replace(".ts",""),g=o.readFileSync(m,"utf-8"),h=Vt.parseActionMetadata(g,p,m);if(h)i.push(h)}}catch{return[]}return i}static parseActionMetadata(e,a,r){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let n=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:a,path:r,handler:`${a}.handle`,description:n?.[1]}}static generateScheduledJobResources(e){let{slug:a,environment:r,jobs:n,taskDefinitionArn:i,clusterArn:o,subnets:c,securityGroups:u=[],roleArn:d,containerName:m="app"}=e,p={},g=0;for(let h of n){if(!h.schedule||!h.enabled)continue;let{rule:y,logicalId:f}=ge.createScheduledJob({slug:a,environment:r,schedule:h.schedule,jobClass:h.name,taskDefinitionArn:i,clusterArn:o,subnets:c,securityGroups:u,roleArn:d,containerName:m});p[f]=y,g++}return{rules:p,count:g}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1662
1662
|
/**
|
|
1663
1663
|
* Job Runner Script
|
|
1664
1664
|
* This script is invoked by ECS scheduled tasks to run jobs
|
|
@@ -2306,14 +2306,14 @@ function resolveTemplate(template, data) {
|
|
|
2306
2306
|
}
|
|
2307
2307
|
return result;
|
|
2308
2308
|
}
|
|
2309
|
-
`;class Te{static LambdaCode={send:tr,receive:rn,deliveryStatus:an};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let a={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)a.SenderId=e.senderId;if(e.shortCode)a.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:a}}}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:Te.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:Te.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:Te.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 a={},r={};Object.assign(a,Te.createPinpointApp({slug:e.slug})),Object.assign(a,Te.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(a,Te.createSmsLambdaRole({slug:e.slug})),Object.assign(a,Te.createMessageLogTable({slug:e.slug})),Object.assign(a,Te.createOptOutTable({slug:e.slug})),Object.assign(a,Te.createNotificationTopic({slug:e.slug}));let n={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},i={Ref:`${e.slug}PinpointApp`},o={Ref:`${e.slug}SmsMessageLogTable`},c={Ref:`${e.slug}SmsOptOutTable`},u={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(a,Te.createSendLambda({slug:e.slug,roleArn:n,pinpointAppId:i,messageLogTable:o,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(a,Te.createReceiveLambda({slug:e.slug,roleArn:n,optOutTable:c,messageLogTable:o,notificationTopicArn:u,webhookUrl:e.webhookUrl}));return Object.assign(a,Te.createDeliveryStatusLambda({slug:e.slug,roleArn:n,messageLogTable:o,notificationTopicArn:u,webhookUrl:e.webhookUrl})),r[`${e.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${e.slug}PinpointApp`}},r[`${e.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${e.slug}SmsSendLambda`,"Arn"]}},r[`${e.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${e.slug}SmsNotificationTopic`}},r[`${e.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${e.slug}SmsMessageLogTable`}},{resources:a,outputs:r}}}function It(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((a)=>a.charAt(0).toUpperCase()+a.slice(1)).join("")||"User"}function sn(e,a){let r=(e||a).replace(/^\/+|\/+$/g,"");if(!r||r.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${a}`);return r}function on(e){let a=e.storage;if(a?.type==="efs"){let n="fileSystemId"in a?a.fileSystemId:void 0;if(!n||typeof n==="string"&&!n.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:n,posixProfile:a.posixProfile}}let r=(a?.type==="s3"?a.bucket??e.bucket:e.bucket)?.trim();if(!r)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:r}}function mn(e,a,r){let n=a.posixProfile??r;if(!n)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let i of[n.uid,n.gid,...n.secondaryGids??[]])if(!Number.isInteger(i)||i<0||i>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${i}`);return{Uid:n.uid,Gid:n.gid,...n.secondaryGids?.length?{SecondaryGids:n.secondaryGids}:{}}}function pn(e,a){return typeof e==="string"?`/${e}/${a}`:{"Fn::Sub":[`/\${FileSystemId}/${a}`,{FileSystemId:e}]}}function gn(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 _o{static create(e){let a=on(e),r=a.type==="efs"?"EFS":"S3",n=e.endpointType??"PUBLIC";if(n==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let i=`${It(e.slug)}${It(e.environment)}Sftp`,o=`${i}Server`,c={},u;if(e.logging!==!1){let d=`${i}LoggingRole`;c[d]={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/*"}]}}]}},u={"Fn::GetAtt":[d,"Arn"]}}c[o]={Type:"AWS::Transfer::Server",Properties:{Domain:r,EndpointType:n,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...n==="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}:{},...u?{LoggingRole:u}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[d,m]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(d))throw Error(`sftp: invalid username ${d}`);if(!m.sshPublicKeys.length)throw Error(`sftp: user ${d} requires at least one SSH public key`);let p=It(d),g=sn(m.homeDirectory,d),h=`${i}${p}User`,y=m.roleArn;if(!y){let f=`${i}${p}Role`,b;if(a.type==="efs")b=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:gn(a.fileSystemId)}];else{let T=`arn:aws:s3:::${a.bucket}`;b=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:T,Condition:{StringLike:{"s3:prefix":[g,`${g}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${T}/${g}/*`}]}c[f]={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:b}}]}},y={"Fn::GetAtt":[f,"Arn"]}}c[h]={Type:"AWS::Transfer::User",DependsOn:[o],Properties:{ServerId:{Ref:o},UserName:d,Role:y,HomeDirectoryType:"PATH",HomeDirectory:a.type==="efs"?pn(a.fileSystemId,g):`/${a.bucket}/${g}`,...a.type==="efs"?{PosixProfile:mn(d,m,a.posixProfile)}:{},SshPublicKeys:m.sshPublicKeys}}}return{resources:c,serverLogicalId:o,domain:r}}}class Fe{static createBedrockRole(e,a){let{slug:r,environment:n,name:i,models:o=["*"],allowStreaming:c=!0}=a,u=i||l({slug:r,environment:n,resourceType:"bedrock-role"}),d=s(u),m=["bedrock:InvokeModel"];if(c)m.push("bedrock:InvokeModelWithResponseStream");let p=o.map((g)=>g==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${g}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:e},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${u}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:m,Resource:p}]}}],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n}]}},logicalId:d}}static createBedrockPolicy(e){let{slug:a,environment:r,name:n,models:i=["*"],allowInvoke:o=!0,allowStreaming:c=!0,allowAsync:u=!1}=e,d=n||l({slug:a,environment:r,resourceType:"bedrock-policy"}),m=s(d),p=[];if(o)p.push("bedrock:InvokeModel");if(c)p.push("bedrock:InvokeModelWithResponseStream");if(u)p.push("bedrock:InvokeModelAsync");let g=i.map((h)=>h==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${h}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:d,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:p,Resource:g}]}}},logicalId:m}}static enableBedrockForLambda(e){return Fe.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return Fe.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return Fe.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,a=["*"],r=!0){let n=["bedrock:InvokeModel"];if(r)n.push("bedrock:InvokeModelWithResponseStream");let i=a.map((o)=>o==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${o}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:n,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,a,r){let{slug:n,environment:i,instanceClass:o="db.t3.micro",allocatedStorage:c=20,storageType:u="gp3",masterUsername:d="admin",masterPassword:m,databaseName:p,subnetIds:g,securityGroupIds:h,encrypted:y=!0,kmsKeyId:f,multiAz:b=!1,backupRetentionDays:T=7,publiclyAccessible:w=!1,enableCloudwatchLogs:I=!0,deletionProtection:v=!0}=r,N=l({slug:n,environment:i,resourceType:`${e}-db`}),R=s(N),k,x;if(g&&g.length>0){let B=l({slug:n,environment:i,resourceType:"db-subnet-group"});x=s(B),k={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:B,DBSubnetGroupDescription:`Subnet group for ${N}`,SubnetIds:g,Tags:[{Key:"Name",Value:B},{Key:"Environment",Value:i}]}}}let M={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:N,DBInstanceClass:o,Engine:e,EngineVersion:a,MasterUsername:d,MasterUserPassword:m,AllocatedStorage:c,StorageType:u,StorageEncrypted:y,MultiAZ:b,BackupRetentionPeriod:T,PubliclyAccessible:w,DeletionProtection:v,Tags:[{Key:"Name",Value:N},{Key:"Environment",Value:i}]}};if(p)M.Properties.DBName=p;if(f)M.Properties.KmsKeyId=f;if(x)M.Properties.DBSubnetGroupName=P.Ref(x);if(h&&h.length>0)M.Properties.VPCSecurityGroups=h;if(I)M.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:M,subnetGroup:k,logicalId:R,subnetGroupId:x}}static createReadReplica(e,a){let{slug:r,environment:n,instanceClass:i="db.t3.micro",securityGroupIds:o,publiclyAccessible:c=!1}=a,u=l({slug:r,environment:n,resourceType:"db-replica"}),d=s(u),m={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:u,DBInstanceClass:i,SourceDBInstanceIdentifier:P.Ref(e),PubliclyAccessible:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n},{Key:"Type",Value:"ReadReplica"}]}};if(o&&o.length>0)m.Properties.VPCSecurityGroups=o;return{replica:m,logicalId:d}}static createParameterGroup(e,a,r){let{slug:n,environment:i,parameters:o={}}=r,c=l({slug:n,environment:i,resourceType:"db-params"}),u=s(c),d=e==="postgres"?`postgres${a.split(".")[0]}`:`mysql${a.split(".")[0]}.${a.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:c,Description:`Parameter group for ${c}`,Family:d,Parameters:o,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:i}]}},logicalId:u}}static enableBackup(e,a=7){return e.Properties.BackupRetentionPeriod=a,e}static createTable(e){let{slug:a,environment:r,tableName:n,partitionKey:i,sortKey:o,billingMode:c="PAY_PER_REQUEST",readCapacity:u=5,writeCapacity:d=5,streamEnabled:m=!1,streamViewType:p="NEW_AND_OLD_IMAGES",encrypted:g=!0,kmsKeyId:h,pointInTimeRecovery:y=!0,ttlAttribute:f}=e,b=n||l({slug:a,environment:r,resourceType:"table"}),T=s(b),w=[{AttributeName:i.name,AttributeType:i.type}];if(o)w.push({AttributeName:o.name,AttributeType:o.type});let I=[{AttributeName:i.name,KeyType:"HASH"}];if(o)I.push({AttributeName:o.name,KeyType:"RANGE"});let v={Type:"AWS::DynamoDB::Table",Properties:{TableName:b,BillingMode:c,AttributeDefinitions:w,KeySchema:I,Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:r}]}};if(c==="PROVISIONED")v.Properties.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(m)v.Properties.StreamSpecification={StreamViewType:p};if(g)v.Properties.SSESpecification={SSEEnabled:!0,SSEType:h?"KMS":"AES256",KMSMasterKeyId:h};if(y)v.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(f)v.Properties.TimeToLiveSpecification={AttributeName:f,Enabled:!0};return{table:v,logicalId:T}}static addGlobalSecondaryIndex(e,a){let{indexName:r,partitionKey:n,sortKey:i,projectionType:o="ALL",nonKeyAttributes:c,readCapacity:u=5,writeCapacity:d=5}=a;if(!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===n.name))e.Properties.AttributeDefinitions.push({AttributeName:n.name,AttributeType:n.type});if(i&&!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===i.name))e.Properties.AttributeDefinitions.push({AttributeName:i.name,AttributeType:i.type});let m=[{AttributeName:n.name,KeyType:"HASH"}];if(i)m.push({AttributeName:i.name,KeyType:"RANGE"});let p={IndexName:r,KeySchema:m,Projection:{ProjectionType:o,NonKeyAttributes:o==="INCLUDE"?c:void 0},ProvisionedThroughput:void 0};if(e.Properties.BillingMode==="PROVISIONED")p.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(!e.Properties.GlobalSecondaryIndexes)e.Properties.GlobalSecondaryIndexes=[];return e.Properties.GlobalSecondaryIndexes.push(p),e}static enableStreams(e,a="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:a},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 vi{static createRedis(e){let{slug:a,environment:r,nodeType:n="cache.t3.micro",engineVersion:i="7.1",port:o=6379,subnetIds:c,securityGroupIds:u,numCacheClusters:d=2,automaticFailover:m=!0,multiAz:p=!0,clusterMode:g=!1,numNodeGroups:h=1,replicasPerNodeGroup:y=1,atRestEncryption:f=!0,transitEncryption:b=!0,authToken:T,kmsKeyId:w,snapshotRetentionDays:I=7,snapshotWindow:v,maintenanceWindow:N}=e,R=l({slug:a,environment:r,resourceType:"redis"}),k=s(R),x,M;if(c&&c.length>0){let _=l({slug:a,environment:r,resourceType:"cache-subnet-group"});M=s(_),x={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:_,Description:`Subnet group for ${R}`,SubnetIds:c,Tags:[{Key:"Name",Value:_},{Key:"Environment",Value:r}]}}}let B={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:R,ReplicationGroupDescription:`Redis cluster for ${a} ${r}`,Engine:"redis",EngineVersion:i,CacheNodeType:n,Port:o,AutomaticFailoverEnabled:m,MultiAZEnabled:p,AtRestEncryptionEnabled:f,TransitEncryptionEnabled:b,SnapshotRetentionLimit:I,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:r}]}};if(g)B.Properties.NumNodeGroups=h,B.Properties.ReplicasPerNodeGroup=y;else B.Properties.NumCacheClusters=d;if(T)B.Properties.AuthToken=T;if(w)B.Properties.KmsKeyId=w;if(M)B.Properties.CacheSubnetGroupName=P.Ref(M);if(u&&u.length>0)B.Properties.SecurityGroupIds=u;if(v)B.Properties.SnapshotWindow=v;if(N)B.Properties.PreferredMaintenanceWindow=N;return{replicationGroup:B,subnetGroup:x,logicalId:k,subnetGroupId:M}}static createMemcached(e){let{slug:a,environment:r,nodeType:n="cache.t3.micro",engineVersion:i="1.6.22",port:o=11211,numCacheNodes:c=2,subnetIds:u,securityGroupIds:d,azMode:m="cross-az",preferredAzs:p,maintenanceWindow:g}=e,h=l({slug:a,environment:r,resourceType:"memcached"}),y=s(h),f,b;if(u&&u.length>0){let w=l({slug:a,environment:r,resourceType:"cache-subnet-group"});b=s(w),f={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:w,Description:`Subnet group for ${h}`,SubnetIds:u,Tags:[{Key:"Name",Value:w},{Key:"Environment",Value:r}]}}}let T={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:h,CacheNodeType:n,Engine:"memcached",EngineVersion:i,NumCacheNodes:c,Port:o,AZMode:m,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};if(b)T.Properties.CacheSubnetGroupName=P.Ref(b);if(d&&d.length>0)T.Properties.VpcSecurityGroupIds=d;if(p&&p.length>0)T.Properties.PreferredAvailabilityZones=p;if(g)T.Properties.PreferredMaintenanceWindow=g;return{cluster:T,subnetGroup:f,logicalId:y,subnetGroupId:b}}static enableClusterMode(e,a=3,r=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=a,e.Properties.ReplicasPerNodeGroup=r,e}static createRedisParameterGroup(e,a){let{slug:r,environment:n,parameters:i={}}=a,o=l({slug:r,environment:n,resourceType:"redis-params"}),c=s(o);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${o}`,Properties:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}},logicalId:c}}static createMemcachedParameterGroup(e,a){let{slug:r,environment:n,parameters:i={}}=a,o=l({slug:r,environment:n,resourceType:"memcached-params"}),c=s(o);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${o}`,Properties:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}},logicalId:c}}static NodeTypes={T3_Micro:"cache.t3.micro",T3_Small:"cache.t3.small",T3_Medium:"cache.t3.medium",T4g_Micro:"cache.t4g.micro",T4g_Small:"cache.t4g.small",T4g_Medium:"cache.t4g.medium",M5_Large:"cache.m5.large",M5_XLarge:"cache.m5.xlarge",M5_2XLarge:"cache.m5.2xlarge",R5_Large:"cache.r5.large",R5_XLarge:"cache.r5.xlarge",R5_2XLarge:"cache.r5.2xlarge",R5_4XLarge:"cache.r5.4xlarge",R6g_Large:"cache.r6g.large",R6g_XLarge:"cache.r6g.xlarge",R6g_2XLarge:"cache.r6g.2xlarge"}}class Ee{static createUser(e){let{slug:a,environment:r,userName:n,groups:i,managedPolicyArns:o}=e,c=n||l({slug:a,environment:r,resourceType:"user"}),u=s(c),d={Type:"AWS::IAM::User",Properties:{UserName:c,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}};if(i&&i.length>0)d.Properties.Groups=i;if(o&&o.length>0)d.Properties.ManagedPolicyArns=o;return{user:d,logicalId:u}}static createRole(e){let{slug:a,environment:r,roleName:n,servicePrincipal:i,awsPrincipal:o,managedPolicyArns:c}=e,u=n||l({slug:a,environment:r,resourceType:"role"}),d=s(u),m={};if(i)m.Service=i;if(o)m.AWS=o;let p={Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.ManagedPolicyArns=c;return{role:p,logicalId:d}}static createGroup(e){let{slug:a,environment:r,groupName:n,managedPolicyArns:i}=e,o=n||l({slug:a,environment:r,resourceType:"group"}),c=s(o),u={Type:"AWS::IAM::Group",Properties:{GroupName:o}};if(i&&i.length>0)u.Properties.ManagedPolicyArns=i;return{group:u,logicalId:c}}static createPolicy(e){let{slug:a,environment:r,policyName:n,description:i,statements:o}=e,c=n||l({slug:a,environment:r,resourceType:"policy"}),u=s(c),d=o.map((m)=>({Sid:m.sid,Effect:m.effect||"Allow",Action:m.actions,Resource:m.resources,Condition:m.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,Description:i||`Managed policy for ${c}`,PolicyDocument:{Version:"2012-10-17",Statement:d}}},logicalId:u}}static attachPolicyToRole(e,a){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(a))e.Properties.ManagedPolicyArns.push(a);return e}static attachPolicyToUser(e,a){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(a))e.Properties.ManagedPolicyArns.push(a);return e}static attachPolicyToGroup(e,a){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(a))e.Properties.ManagedPolicyArns.push(a);return e}static addInlinePolicyToRole(e,a,r){if(!e.Properties.Policies)e.Properties.Policies=[];let n=r.map((i)=>({Effect:i.effect||"Allow",Action:i.actions,Resource:i.resources}));return e.Properties.Policies.push({PolicyName:a,PolicyDocument:{Version:"2012-10-17",Statement:n}}),e}static addInlinePolicyToUser(e,a,r){if(!e.Properties.Policies)e.Properties.Policies=[];let n=r.map((i)=>({Effect:i.effect||"Allow",Action:i.actions,Resource:i.resources}));return e.Properties.Policies.push({PolicyName:a,PolicyDocument:{Version:"2012-10-17",Statement:n}}),e}static createAccessKey(e,a){let{slug:r,environment:n,status:i="Active"}=a,o=l({slug:r,environment:n,resourceType:"access-key"}),c=s(o);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:P.Ref(e),Status:i}},logicalId:c}}static createInstanceProfile(e,a){let{slug:r,environment:n,profileName:i}=a,o=i||l({slug:r,environment:n,resourceType:"instance-profile"}),c=s(o);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:o,Roles:[P.Ref(e)]}},logicalId:c}}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:a,environment:r,permissions:n,createAccessKey:i=!0}=e,o={},c=[];if(n.s3Buckets&&n.s3Buckets.length>0)c.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...n.s3Buckets,...n.s3Buckets.map((y)=>`${y}/*`)]});if(n.cloudFrontDistributions&&n.cloudFrontDistributions.length>0)c.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:n.cloudFrontDistributions});if(n.ecrRepositories&&n.ecrRepositories.length>0)c.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:n.ecrRepositories}),c.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(n.ecsServices&&n.ecsServices.length>0)c.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:n.ecsServices}),c.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),c.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(n.cloudFormationStacks&&n.cloudFormationStacks.length>0)c.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:n.cloudFormationStacks});if(n.lambdaFunctions&&n.lambdaFunctions.length>0)c.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:n.lambdaFunctions});if(n.secretsManagerSecrets&&n.secretsManagerSecrets.length>0)c.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:n.secretsManagerSecrets});let{policy:u,logicalId:d}=Ee.createPolicy({slug:a,environment:r,policyName:l({slug:a,environment:r,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${a} (${r})`,statements:c});o[d]=u;let{user:m,logicalId:p}=Ee.createUser({slug:a,environment:r,userName:l({slug:a,environment:r,resourceType:"cicd-user"}),managedPolicyArns:[P.Ref(d)]});o[p]=m;let g,h;if(i){let y=Ee.createAccessKey(p,{slug:a,environment:r});g=y.accessKey,h=y.logicalId,o[h]=g}return{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:h,policyLogicalId:d,resources:o}}static createCrossAccountRole(e){let{slug:a,environment:r,trustedAccountIds:n,externalId:i,permissions:o,maxSessionDuration:c=3600}=e,u={},{policy:d,logicalId:m}=Ee.createPolicy({slug:a,environment:r,policyName:l({slug:a,environment:r,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${a} (${r})`,statements:o});u[m]=d;let p=l({slug:a,environment:r,resourceType:"cross-account-role"}),g=s(p),h={};if(i)h.StringEquals={"sts:ExternalId":i};let y={Type:"AWS::IAM::Role",Properties:{RoleName:p,MaxSessionDuration:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:n.map((f)=>`arn:aws:iam::${f}:root`)},Action:"sts:AssumeRole",...Object.keys(h).length>0?{Condition:h}:{}}]},ManagedPolicyArns:[P.Ref(m)],Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Cross-Account Access"}]}};return u[g]=y,{role:y,policy:d,roleLogicalId:g,policyLogicalId:m,resources:u}}static createCliUser(e){let{slug:a,environment:r,permissions:n="readonly"}=e,i={},o=[],c=[];switch(n){case"readonly":c=[Ee.ManagedPolicies.ReadOnlyAccess];break;case"deploy":o=[{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":c=[Ee.ManagedPolicies.AdministratorAccess];break}let u,d;if(o.length>0){let y=Ee.createPolicy({slug:a,environment:r,policyName:l({slug:a,environment:r,resourceType:"cli-policy"}),description:`CLI access policy for ${a} (${r})`,statements:o});u=y.policy,d=y.logicalId,i[d]=u,c=[P.Ref(d)]}let{user:m,logicalId:p}=Ee.createUser({slug:a,environment:r,userName:l({slug:a,environment:r,resourceType:"cli-user"}),managedPolicyArns:c});i[p]=m;let{accessKey:g,logicalId:h}=Ee.createAccessKey(p,{slug:a,environment:r});return i[h]=g,{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:h,policyLogicalId:d,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((a)=>`${a}/*`)}],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 xo{static createRestApi(e){let{slug:a,environment:r,name:n,description:i,endpointType:o="REGIONAL",binaryMediaTypes:c,compressionSize:u}=e,d=n||l({slug:a,environment:r,resourceType:"rest-api"}),m=s(d),p={Type:"AWS::ApiGateway::RestApi",Properties:{Name:d,Description:i||`REST API for ${a} ${r}`,EndpointConfiguration:{Types:[o]},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.BinaryMediaTypes=c;if(u!==void 0)p.Properties.MinimumCompressionSize=u;return{restApi:p,logicalId:m}}static createHttpApi(e){let{slug:a,environment:r,name:n,description:i,corsEnabled:o=!0,corsOrigins:c=["*"],corsMethods:u=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:d=["*"],corsMaxAge:m=86400,corsAllowCredentials:p=!1}=e,g=n||l({slug:a,environment:r,resourceType:"http-api"}),h=s(g),y={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:g,Description:i||`HTTP API for ${a} ${r}`,ProtocolType:"HTTP",Tags:{Name:g,Environment:r}}};if(o)y.Properties.CorsConfiguration={AllowOrigins:c,AllowMethods:u,AllowHeaders:d,MaxAge:m,AllowCredentials:p};return{httpApi:y,logicalId:h}}static createWebSocketApi(e){let{slug:a,environment:r,name:n,description:i}=e,o=n||l({slug:a,environment:r,resourceType:"ws-api"}),c=s(o);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:o,Description:i||`WebSocket API for ${a} ${r}`,ProtocolType:"WEBSOCKET",Tags:{Name:o,Environment:r}}},logicalId:c}}static createDeployment(e,a){let{slug:r,environment:n,description:i}=a,o=l({slug:r,environment:n,resourceType:"api-deployment"}),c=s(o);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:P.Ref(e),Description:i||`Deployment for ${o}`}},logicalId:c}}static createStage(e,a,r){let{slug:n,environment:i,stageName:o,description:c,cacheEnabled:u=!1,cacheSize:d="0.5",variables:m,throttling:p}=r,g=l({slug:n,environment:i,resourceType:"api-stage"}),h=s(g),y={Type:"AWS::ApiGateway::Stage",Properties:{StageName:o||i,RestApiId:P.Ref(e),DeploymentId:P.Ref(a),Description:c,CacheClusterEnabled:u,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:i}]}};if(u)y.Properties.CacheClusterSize=d;if(m)y.Properties.Variables=m;if(p)y.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:p.burstLimit,ThrottlingRateLimit:p.rateLimit}];return{stage:y,logicalId:h}}static createAuthorizer(e,a){let{slug:r,environment:n,name:i,type:o,functionArn:c,identitySource:u,userPoolArns:d,ttl:m=300}=a,p=i||l({slug:r,environment:n,resourceType:"api-authorizer"}),g=s(p),h={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:p,Type:o,RestApiId:P.Ref(e),AuthorizerResultTtlInSeconds:m}};if(o==="TOKEN"||o==="REQUEST"){if(!c)throw Error("Lambda authorizer requires functionArn");h.Properties.AuthorizerUri=c,h.Properties.IdentitySource=u||"method.request.header.Authorization"}if(o==="COGNITO_USER_POOLS"){if(!d||d.length===0)throw Error("Cognito authorizer requires userPoolArns");h.Properties.ProviderARNs=d,h.Properties.IdentitySource=u||"method.request.header.Authorization"}return{authorizer:h,logicalId:g}}static setCors(e,a={}){let{origins:r=["*"],methods:n=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:i=["*"],maxAge:o=86400,allowCredentials:c=!1}=a;return e.Properties.CorsConfiguration={AllowOrigins:r,AllowMethods:n,AllowHeaders:i,MaxAge:o,AllowCredentials:c},e}static addThrottling(e,a=5000,r=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:a,ThrottlingRateLimit:r}),e}static enableCaching(e,a="0.5",r=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=a,!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:r}),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 ke{static createTopic(e){let{slug:a,environment:r,topicName:n,displayName:i,encrypted:o=!1,kmsKeyId:c}=e,u=n||l({slug:a,environment:r,resourceType:"topic"}),d=s(u),m={Type:"AWS::SNS::Topic",Properties:{TopicName:u,DisplayName:i||u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(o&&c)m.Properties.KmsMasterKeyId=c;return{topic:m,logicalId:d}}static subscribe(e,a){let{slug:r,environment:n,protocol:i,endpoint:o,filterPolicy:c,rawMessageDelivery:u=!1}=a,d=l({slug:r,environment:n,resourceType:"subscription"}),m=o.replace(/[^a-zA-Z0-9]/g,""),p=m.length>12?m.slice(-12):m,g=s(`${d}-${i}-${p}`),h={Type:"AWS::SNS::Subscription",Properties:{TopicArn:P.Ref(e),Protocol:i,Endpoint:o,RawMessageDelivery:u}};if(c)h.Properties.FilterPolicy=c;return{subscription:h,logicalId:g}}static subscribeEmail(e,a,r){return ke.subscribe(e,{...r,protocol:"email",endpoint:a})}static subscribeLambda(e,a,r){return ke.subscribe(e,{...r,protocol:"lambda",endpoint:a,rawMessageDelivery:!0})}static subscribeSqs(e,a,r){return ke.subscribe(e,{...r,protocol:"sqs",endpoint:a})}static subscribeHttp(e,a,r){let n=a.startsWith("https://")?"https":"http";return ke.subscribe(e,{...r,protocol:n,endpoint:a})}static subscribeSms(e,a,r){return ke.subscribe(e,{...r,protocol:"sms",endpoint:a})}static setTopicPolicy(e,a){let{slug:r,environment:n,allowedPrincipals:i,allowedServices:o,actions:c="SNS:Publish"}=a,u=l({slug:r,environment:n,resourceType:"topic-policy"}),d=s(u),m={};if(i)m.AWS=i;if(o)m.Service=o;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[P.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:c,Resource:P.Ref(e)}]}}},logicalId:d}}static allowCloudWatchAlarms(e,a){return ke.setTopicPolicy(e,{...a,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,a){return ke.setTopicPolicy(e,{...a,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,a){return ke.setTopicPolicy(e,{...a,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,a){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=a,e}static addInlineSubscription(e,a,r){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:a,Endpoint:r}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,a,r)=>({[e]:[{numeric:[">=",a,"<=",r]}]}),prefix:(e,a)=>({[e]:[{prefix:a}]}),and:(...e)=>Object.assign({},...e),exists:(e,a)=>({[e]:[{exists:a}]})};static UseCases={createAlertTopic:(e)=>ke.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>ke.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>ke.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class Od{static createStateMachine(e){let{slug:a,environment:r,stateMachineName:n,type:i="STANDARD",definition:o,roleArn:c,loggingConfiguration:u,tracingConfiguration:d}=e,m=n||l({slug:a,environment:r,resourceType:"state-machine"}),p=s(m),g,h,y;if(c)y=c;else{let b=l({slug:a,environment:r,resourceType:"state-machine-role"});h=s(b),g={Type:"AWS::IAM::Role",Properties:{RoleName:b,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:b},{Key:"Environment",Value:r}]}},y=P.GetAtt(h,"Arn")}let f={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:m,StateMachineType:i,DefinitionString:JSON.stringify(o),RoleArn:y,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(u)f.Properties.LoggingConfiguration={Level:u.level,IncludeExecutionData:u.includeExecutionData,Destinations:u.destinations?.map((b)=>({CloudWatchLogsLogGroup:{LogGroupArn:b}}))};if(d)f.Properties.TracingConfiguration={Enabled:d.enabled};return{stateMachine:f,logicalId:p,role:g,roleLogicalId:h}}static createLambdaTask(e,a){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:a?.parameters||{"Input.$":"$"}},ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createDynamoDBTask(e,a,r,n){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:a,...r},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createSNSPublishTask(e,a,r){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:a},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSQSSendMessageTask(e,a,r){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:a},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.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,a){return{Type:"Choice",Choices:e,Default:a}}static createParallelState(e,a){return{Type:"Parallel",Branches:e,ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createMapState(e,a){return{Type:"Map",ItemsPath:a?.itemsPath||"$.items",Iterator:e,MaxConcurrency:a?.maxConcurrency,ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,a){return{Type:"Fail",Error:e,Cause:a}}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,a,r,n)=>({ErrorEquals:e,IntervalSeconds:a,MaxAttempts:r,BackoffRate:n})};static CatchPolicies={all:(e,a)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:a||"$.error"}),specific:(e,a,r)=>({ErrorEquals:e,Next:a,ResultPath:r||"$.error"})};static Patterns={sequential:(e,a,r)=>{let n={};return r.forEach((i,o)=>{let c=o===r.length-1;n[i.name]={...i.state,Next:c?void 0:r[o+1].name,End:c}}),{Comment:"Sequential workflow",StartAt:r[0].name,States:n}},fanout:(e,a,r)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:r.map((n)=>n.definition),End:!0}}}),map:(e,a,r,n)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:r,MaxConcurrency:n,End:!0}}}),withErrorHandling:(e,a,r,n)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...r,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:n,Success:{Type:"Succeed"}}})}}class Ti{static createAlarm(e){let{slug:a,environment:r,alarmName:n,metricName:i,namespace:o,statistic:c="Average",period:u=300,evaluationPeriods:d=1,threshold:m,comparisonOperator:p,treatMissingData:g="notBreaching",actionsEnabled:h=!0,alarmActions:y,okActions:f,insufficientDataActions:b,dimensions:T,unit:w,datapointsToAlarm:I}=e,v=n||l({slug:a,environment:r,resourceType:"alarm"}),N=s(v),R={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:v,MetricName:i,Namespace:o,Statistic:c,Period:u,EvaluationPeriods:d,Threshold:m,ComparisonOperator:p,TreatMissingData:g,ActionsEnabled:h}};if(y&&y.length>0)R.Properties.AlarmActions=y;if(f&&f.length>0)R.Properties.OKActions=f;if(b&&b.length>0)R.Properties.InsufficientDataActions=b;if(T)R.Properties.Dimensions=Object.entries(T).map(([k,x])=>({Name:k,Value:x}));if(w)R.Properties.Unit=w;if(I!==void 0)R.Properties.DatapointsToAlarm=I;return{alarm:R,logicalId:N}}static createCompositeAlarm(e){let{slug:a,environment:r,alarmName:n,alarmRule:i,actionsEnabled:o=!0,alarmActions:c,okActions:u,insufficientDataActions:d}=e,m=n||l({slug:a,environment:r,resourceType:"composite-alarm"}),p=s(m),g={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:m,AlarmRule:i,ActionsEnabled:o}};if(c&&c.length>0)g.Properties.AlarmActions=c;if(u&&u.length>0)g.Properties.OKActions=u;if(d&&d.length>0)g.Properties.InsufficientDataActions=d;return{alarm:g,logicalId:p}}static createDashboard(e){let{slug:a,environment:r,dashboardName:n,widgets:i}=e,o=n||l({slug:a,environment:r,resourceType:"dashboard"}),c=s(o),u={widgets:i.map((d)=>({type:d.type,x:d.x,y:d.y,width:d.width,height:d.height,properties:d.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:o,DashboardBody:JSON.stringify(u)}},logicalId:c}}static createLogGroup(e){let{slug:a,environment:r,logGroupName:n,retentionInDays:i,kmsKeyId:o}=e,c=n||l({slug:a,environment:r,resourceType:"log-group"}),u=s(c),d={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:c}};if(i!==void 0)d.Properties.RetentionInDays=i;if(o)d.Properties.KmsKeyId=o;return{logGroup:d,logicalId:u}}static createLogStream(e,a){let{slug:r,environment:n,logStreamName:i}=a,o=i||l({slug:r,environment:n,resourceType:"log-stream"}),c=s(o);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:P.Ref(e),LogStreamName:o}},logicalId:c}}static createMetricFilter(e,a){let{slug:r,environment:n,filterName:i,filterPattern:o,metricTransformations:c}=a,u=i||l({slug:r,environment:n,resourceType:"metric-filter"}),d=s(u);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:P.Ref(e),FilterPattern:o,MetricTransformations:c.map((m)=>({MetricName:m.metricName,MetricNamespace:m.metricNamespace,MetricValue:m.metricValue,DefaultValue:m.defaultValue,Unit:m.unit}))}},logicalId:d}}static AlarmTypes={highCpu:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:i?[i]:void 0}),highMemory:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:i?[i]:void 0}),highDisk:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:i?[i]:void 0}),lambdaErrors:(e,a,r,n=5,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:i?[i]:void 0}),lambdaThrottles:(e,a,r,n=10,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:i?[i]:void 0}),apiGateway5xxErrors:(e,a,r,n=10,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:i?[i]:void 0}),apiGateway4xxErrors:(e,a,r,n=50,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:i?[i]:void 0}),dynamoDBThrottles:(e,a,r,n=5,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:r},alarmActions:i?[i]:void 0}),rdsCpu:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:i?[i]:void 0}),rdsFreeStorage:(e,a,r,n=5368709120,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:i?[i]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,a,r,n=100,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:r},alarmActions:i?[i]:void 0}),albUnhealthyTargets:(e,a,r,n,i=1,o)=>({slug:e,environment:a,alarmName:`${e}-${a}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:r,TargetGroup:n},alarmActions:o?[o]:void 0}),sesBounceRate:(e,a,r=5,n)=>({slug:e,environment:a,alarmName:`${e}-${a}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:n?[n]:void 0}),sesComplaintRate:(e,a,r=0.1,n)=>({slug:e,environment:a,alarmName:`${e}-${a}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:n?[n]:void 0}),smsDeliveryFailure:(e,a,r,n=10,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:r},alarmActions:i?[i]:void 0}),smsSpendLimit:(e,a,r=100,n)=>({slug:e,environment:a,alarmName:`${e}-${a}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",alarmActions:n?[n]:void 0}),connectMissedCalls:(e,a,r,n=5,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:i?[i]:void 0})};static DashboardWidgets={metric:(e,a,r,n,i,o)=>({type:"metric",x:e,y:a,width:r,height:n,properties:{metrics:i,title:o||"Metrics",region:"us-east-1",period:300}}),text:(e,a,r,n,i)=>({type:"text",x:e,y:a,width:r,height:n,properties:{markdown:i}}),log:(e,a,r,n,i,o)=>({type:"log",x:e,y:a,width:r,height:n,properties:{query:`SOURCE '${i.join("' | SOURCE '")}'
|
|
2309
|
+
`;class Te{static LambdaCode={send:tr,receive:rn,deliveryStatus:an};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let a={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)a.SenderId=e.senderId;if(e.shortCode)a.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:a}}}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:Te.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:Te.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:Te.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 a={},r={};Object.assign(a,Te.createPinpointApp({slug:e.slug})),Object.assign(a,Te.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(a,Te.createSmsLambdaRole({slug:e.slug})),Object.assign(a,Te.createMessageLogTable({slug:e.slug})),Object.assign(a,Te.createOptOutTable({slug:e.slug})),Object.assign(a,Te.createNotificationTopic({slug:e.slug}));let n={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},i={Ref:`${e.slug}PinpointApp`},o={Ref:`${e.slug}SmsMessageLogTable`},c={Ref:`${e.slug}SmsOptOutTable`},u={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(a,Te.createSendLambda({slug:e.slug,roleArn:n,pinpointAppId:i,messageLogTable:o,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(a,Te.createReceiveLambda({slug:e.slug,roleArn:n,optOutTable:c,messageLogTable:o,notificationTopicArn:u,webhookUrl:e.webhookUrl}));return Object.assign(a,Te.createDeliveryStatusLambda({slug:e.slug,roleArn:n,messageLogTable:o,notificationTopicArn:u,webhookUrl:e.webhookUrl})),r[`${e.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${e.slug}PinpointApp`}},r[`${e.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${e.slug}SmsSendLambda`,"Arn"]}},r[`${e.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${e.slug}SmsNotificationTopic`}},r[`${e.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${e.slug}SmsMessageLogTable`}},{resources:a,outputs:r}}}function It(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((a)=>a.charAt(0).toUpperCase()+a.slice(1)).join("")||"User"}function sn(e,a){let r=(e||a).replace(/^\/+|\/+$/g,"");if(!r||r.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${a}`);return r}function on(e){let a=e.storage;if(a?.type==="efs"){let n="fileSystemId"in a?a.fileSystemId:void 0;if(!n||typeof n==="string"&&!n.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:n,posixProfile:a.posixProfile}}let r=(a?.type==="s3"?a.bucket??e.bucket:e.bucket)?.trim();if(!r)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:r}}function mn(e,a,r){let n=a.posixProfile??r;if(!n)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let i of[n.uid,n.gid,...n.secondaryGids??[]])if(!Number.isInteger(i)||i<0||i>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${i}`);return{Uid:n.uid,Gid:n.gid,...n.secondaryGids?.length?{SecondaryGids:n.secondaryGids}:{}}}function pn(e,a){return typeof e==="string"?`/${e}/${a}`:{"Fn::Sub":[`/\${FileSystemId}/${a}`,{FileSystemId:e}]}}function gn(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 _o{static create(e){let a=on(e),r=a.type==="efs"?"EFS":"S3",n=e.endpointType??"PUBLIC";if(n==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let i=`${It(e.slug)}${It(e.environment)}Sftp`,o=`${i}Server`,c={},u;if(e.logging!==!1){let d=`${i}LoggingRole`;c[d]={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/*"}]}}]}},u={"Fn::GetAtt":[d,"Arn"]}}c[o]={Type:"AWS::Transfer::Server",Properties:{Domain:r,EndpointType:n,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...n==="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}:{},...u?{LoggingRole:u}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[d,m]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(d))throw Error(`sftp: invalid username ${d}`);if(!m.sshPublicKeys.length)throw Error(`sftp: user ${d} requires at least one SSH public key`);let p=It(d),g=sn(m.homeDirectory,d),h=`${i}${p}User`,y=m.roleArn;if(!y){let f=`${i}${p}Role`,b;if(a.type==="efs")b=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:gn(a.fileSystemId)}];else{let v=`arn:aws:s3:::${a.bucket}`;b=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:v,Condition:{StringLike:{"s3:prefix":[g,`${g}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${v}/${g}/*`}]}c[f]={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:b}}]}},y={"Fn::GetAtt":[f,"Arn"]}}c[h]={Type:"AWS::Transfer::User",DependsOn:[o],Properties:{ServerId:{Ref:o},UserName:d,Role:y,HomeDirectoryType:"PATH",HomeDirectory:a.type==="efs"?pn(a.fileSystemId,g):`/${a.bucket}/${g}`,...a.type==="efs"?{PosixProfile:mn(d,m,a.posixProfile)}:{},SshPublicKeys:m.sshPublicKeys}}}return{resources:c,serverLogicalId:o,domain:r}}}class Fe{static createBedrockRole(e,a){let{slug:r,environment:n,name:i,models:o=["*"],allowStreaming:c=!0}=a,u=i||l({slug:r,environment:n,resourceType:"bedrock-role"}),d=s(u),m=["bedrock:InvokeModel"];if(c)m.push("bedrock:InvokeModelWithResponseStream");let p=o.map((g)=>g==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${g}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:e},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${u}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:m,Resource:p}]}}],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n}]}},logicalId:d}}static createBedrockPolicy(e){let{slug:a,environment:r,name:n,models:i=["*"],allowInvoke:o=!0,allowStreaming:c=!0,allowAsync:u=!1}=e,d=n||l({slug:a,environment:r,resourceType:"bedrock-policy"}),m=s(d),p=[];if(o)p.push("bedrock:InvokeModel");if(c)p.push("bedrock:InvokeModelWithResponseStream");if(u)p.push("bedrock:InvokeModelAsync");let g=i.map((h)=>h==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${h}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:d,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:p,Resource:g}]}}},logicalId:m}}static enableBedrockForLambda(e){return Fe.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return Fe.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return Fe.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,a=["*"],r=!0){let n=["bedrock:InvokeModel"];if(r)n.push("bedrock:InvokeModelWithResponseStream");let i=a.map((o)=>o==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${o}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:n,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,a,r){let{slug:n,environment:i,instanceClass:o="db.t3.micro",allocatedStorage:c=20,storageType:u="gp3",masterUsername:d="admin",masterPassword:m,databaseName:p,subnetIds:g,securityGroupIds:h,encrypted:y=!0,kmsKeyId:f,multiAz:b=!1,backupRetentionDays:v=7,publiclyAccessible:T=!1,enableCloudwatchLogs:I=!0,deletionProtection:C=!0}=r,N=l({slug:n,environment:i,resourceType:`${e}-db`}),R=s(N),k,x;if(g&&g.length>0){let B=l({slug:n,environment:i,resourceType:"db-subnet-group"});x=s(B),k={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:B,DBSubnetGroupDescription:`Subnet group for ${N}`,SubnetIds:g,Tags:[{Key:"Name",Value:B},{Key:"Environment",Value:i}]}}}let M={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:N,DBInstanceClass:o,Engine:e,EngineVersion:a,MasterUsername:d,MasterUserPassword:m,AllocatedStorage:c,StorageType:u,StorageEncrypted:y,MultiAZ:b,BackupRetentionPeriod:v,PubliclyAccessible:T,DeletionProtection:C,Tags:[{Key:"Name",Value:N},{Key:"Environment",Value:i}]}};if(p)M.Properties.DBName=p;if(f)M.Properties.KmsKeyId=f;if(x)M.Properties.DBSubnetGroupName=P.Ref(x);if(h&&h.length>0)M.Properties.VPCSecurityGroups=h;if(I)M.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:M,subnetGroup:k,logicalId:R,subnetGroupId:x}}static createReadReplica(e,a){let{slug:r,environment:n,instanceClass:i="db.t3.micro",securityGroupIds:o,publiclyAccessible:c=!1}=a,u=l({slug:r,environment:n,resourceType:"db-replica"}),d=s(u),m={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:u,DBInstanceClass:i,SourceDBInstanceIdentifier:P.Ref(e),PubliclyAccessible:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:n},{Key:"Type",Value:"ReadReplica"}]}};if(o&&o.length>0)m.Properties.VPCSecurityGroups=o;return{replica:m,logicalId:d}}static createParameterGroup(e,a,r){let{slug:n,environment:i,parameters:o={}}=r,c=l({slug:n,environment:i,resourceType:"db-params"}),u=s(c),d=e==="postgres"?`postgres${a.split(".")[0]}`:`mysql${a.split(".")[0]}.${a.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:c,Description:`Parameter group for ${c}`,Family:d,Parameters:o,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:i}]}},logicalId:u}}static enableBackup(e,a=7){return e.Properties.BackupRetentionPeriod=a,e}static createTable(e){let{slug:a,environment:r,tableName:n,partitionKey:i,sortKey:o,billingMode:c="PAY_PER_REQUEST",readCapacity:u=5,writeCapacity:d=5,streamEnabled:m=!1,streamViewType:p="NEW_AND_OLD_IMAGES",encrypted:g=!0,kmsKeyId:h,pointInTimeRecovery:y=!0,ttlAttribute:f}=e,b=n||l({slug:a,environment:r,resourceType:"table"}),v=s(b),T=[{AttributeName:i.name,AttributeType:i.type}];if(o)T.push({AttributeName:o.name,AttributeType:o.type});let I=[{AttributeName:i.name,KeyType:"HASH"}];if(o)I.push({AttributeName:o.name,KeyType:"RANGE"});let C={Type:"AWS::DynamoDB::Table",Properties:{TableName:b,BillingMode:c,AttributeDefinitions:T,KeySchema:I,Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:r}]}};if(c==="PROVISIONED")C.Properties.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(m)C.Properties.StreamSpecification={StreamViewType:p};if(g)C.Properties.SSESpecification={SSEEnabled:!0,SSEType:h?"KMS":"AES256",KMSMasterKeyId:h};if(y)C.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(f)C.Properties.TimeToLiveSpecification={AttributeName:f,Enabled:!0};return{table:C,logicalId:v}}static addGlobalSecondaryIndex(e,a){let{indexName:r,partitionKey:n,sortKey:i,projectionType:o="ALL",nonKeyAttributes:c,readCapacity:u=5,writeCapacity:d=5}=a;if(!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===n.name))e.Properties.AttributeDefinitions.push({AttributeName:n.name,AttributeType:n.type});if(i&&!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===i.name))e.Properties.AttributeDefinitions.push({AttributeName:i.name,AttributeType:i.type});let m=[{AttributeName:n.name,KeyType:"HASH"}];if(i)m.push({AttributeName:i.name,KeyType:"RANGE"});let p={IndexName:r,KeySchema:m,Projection:{ProjectionType:o,NonKeyAttributes:o==="INCLUDE"?c:void 0},ProvisionedThroughput:void 0};if(e.Properties.BillingMode==="PROVISIONED")p.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(!e.Properties.GlobalSecondaryIndexes)e.Properties.GlobalSecondaryIndexes=[];return e.Properties.GlobalSecondaryIndexes.push(p),e}static enableStreams(e,a="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:a},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 vi{static createRedis(e){let{slug:a,environment:r,nodeType:n="cache.t3.micro",engineVersion:i="7.1",port:o=6379,subnetIds:c,securityGroupIds:u,numCacheClusters:d=2,automaticFailover:m=!0,multiAz:p=!0,clusterMode:g=!1,numNodeGroups:h=1,replicasPerNodeGroup:y=1,atRestEncryption:f=!0,transitEncryption:b=!0,authToken:v,kmsKeyId:T,snapshotRetentionDays:I=7,snapshotWindow:C,maintenanceWindow:N}=e,R=l({slug:a,environment:r,resourceType:"redis"}),k=s(R),x,M;if(c&&c.length>0){let _=l({slug:a,environment:r,resourceType:"cache-subnet-group"});M=s(_),x={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:_,Description:`Subnet group for ${R}`,SubnetIds:c,Tags:[{Key:"Name",Value:_},{Key:"Environment",Value:r}]}}}let B={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:R,ReplicationGroupDescription:`Redis cluster for ${a} ${r}`,Engine:"redis",EngineVersion:i,CacheNodeType:n,Port:o,AutomaticFailoverEnabled:m,MultiAZEnabled:p,AtRestEncryptionEnabled:f,TransitEncryptionEnabled:b,SnapshotRetentionLimit:I,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:r}]}};if(g)B.Properties.NumNodeGroups=h,B.Properties.ReplicasPerNodeGroup=y;else B.Properties.NumCacheClusters=d;if(v)B.Properties.AuthToken=v;if(T)B.Properties.KmsKeyId=T;if(M)B.Properties.CacheSubnetGroupName=P.Ref(M);if(u&&u.length>0)B.Properties.SecurityGroupIds=u;if(C)B.Properties.SnapshotWindow=C;if(N)B.Properties.PreferredMaintenanceWindow=N;return{replicationGroup:B,subnetGroup:x,logicalId:k,subnetGroupId:M}}static createMemcached(e){let{slug:a,environment:r,nodeType:n="cache.t3.micro",engineVersion:i="1.6.22",port:o=11211,numCacheNodes:c=2,subnetIds:u,securityGroupIds:d,azMode:m="cross-az",preferredAzs:p,maintenanceWindow:g}=e,h=l({slug:a,environment:r,resourceType:"memcached"}),y=s(h),f,b;if(u&&u.length>0){let T=l({slug:a,environment:r,resourceType:"cache-subnet-group"});b=s(T),f={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:T,Description:`Subnet group for ${h}`,SubnetIds:u,Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:r}]}}}let v={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:h,CacheNodeType:n,Engine:"memcached",EngineVersion:i,NumCacheNodes:c,Port:o,AZMode:m,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};if(b)v.Properties.CacheSubnetGroupName=P.Ref(b);if(d&&d.length>0)v.Properties.VpcSecurityGroupIds=d;if(p&&p.length>0)v.Properties.PreferredAvailabilityZones=p;if(g)v.Properties.PreferredMaintenanceWindow=g;return{cluster:v,subnetGroup:f,logicalId:y,subnetGroupId:b}}static enableClusterMode(e,a=3,r=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=a,e.Properties.ReplicasPerNodeGroup=r,e}static createRedisParameterGroup(e,a){let{slug:r,environment:n,parameters:i={}}=a,o=l({slug:r,environment:n,resourceType:"redis-params"}),c=s(o);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${o}`,Properties:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}},logicalId:c}}static createMemcachedParameterGroup(e,a){let{slug:r,environment:n,parameters:i={}}=a,o=l({slug:r,environment:n,resourceType:"memcached-params"}),c=s(o);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${o}`,Properties:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:n}]}},logicalId:c}}static NodeTypes={T3_Micro:"cache.t3.micro",T3_Small:"cache.t3.small",T3_Medium:"cache.t3.medium",T4g_Micro:"cache.t4g.micro",T4g_Small:"cache.t4g.small",T4g_Medium:"cache.t4g.medium",M5_Large:"cache.m5.large",M5_XLarge:"cache.m5.xlarge",M5_2XLarge:"cache.m5.2xlarge",R5_Large:"cache.r5.large",R5_XLarge:"cache.r5.xlarge",R5_2XLarge:"cache.r5.2xlarge",R5_4XLarge:"cache.r5.4xlarge",R6g_Large:"cache.r6g.large",R6g_XLarge:"cache.r6g.xlarge",R6g_2XLarge:"cache.r6g.2xlarge"}}class Ee{static createUser(e){let{slug:a,environment:r,userName:n,groups:i,managedPolicyArns:o}=e,c=n||l({slug:a,environment:r,resourceType:"user"}),u=s(c),d={Type:"AWS::IAM::User",Properties:{UserName:c,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}};if(i&&i.length>0)d.Properties.Groups=i;if(o&&o.length>0)d.Properties.ManagedPolicyArns=o;return{user:d,logicalId:u}}static createRole(e){let{slug:a,environment:r,roleName:n,servicePrincipal:i,awsPrincipal:o,managedPolicyArns:c}=e,u=n||l({slug:a,environment:r,resourceType:"role"}),d=s(u),m={};if(i)m.Service=i;if(o)m.AWS=o;let p={Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.ManagedPolicyArns=c;return{role:p,logicalId:d}}static createGroup(e){let{slug:a,environment:r,groupName:n,managedPolicyArns:i}=e,o=n||l({slug:a,environment:r,resourceType:"group"}),c=s(o),u={Type:"AWS::IAM::Group",Properties:{GroupName:o}};if(i&&i.length>0)u.Properties.ManagedPolicyArns=i;return{group:u,logicalId:c}}static createPolicy(e){let{slug:a,environment:r,policyName:n,description:i,statements:o}=e,c=n||l({slug:a,environment:r,resourceType:"policy"}),u=s(c),d=o.map((m)=>({Sid:m.sid,Effect:m.effect||"Allow",Action:m.actions,Resource:m.resources,Condition:m.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,Description:i||`Managed policy for ${c}`,PolicyDocument:{Version:"2012-10-17",Statement:d}}},logicalId:u}}static attachPolicyToRole(e,a){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(a))e.Properties.ManagedPolicyArns.push(a);return e}static attachPolicyToUser(e,a){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(a))e.Properties.ManagedPolicyArns.push(a);return e}static attachPolicyToGroup(e,a){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(a))e.Properties.ManagedPolicyArns.push(a);return e}static addInlinePolicyToRole(e,a,r){if(!e.Properties.Policies)e.Properties.Policies=[];let n=r.map((i)=>({Effect:i.effect||"Allow",Action:i.actions,Resource:i.resources}));return e.Properties.Policies.push({PolicyName:a,PolicyDocument:{Version:"2012-10-17",Statement:n}}),e}static addInlinePolicyToUser(e,a,r){if(!e.Properties.Policies)e.Properties.Policies=[];let n=r.map((i)=>({Effect:i.effect||"Allow",Action:i.actions,Resource:i.resources}));return e.Properties.Policies.push({PolicyName:a,PolicyDocument:{Version:"2012-10-17",Statement:n}}),e}static createAccessKey(e,a){let{slug:r,environment:n,status:i="Active"}=a,o=l({slug:r,environment:n,resourceType:"access-key"}),c=s(o);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:P.Ref(e),Status:i}},logicalId:c}}static createInstanceProfile(e,a){let{slug:r,environment:n,profileName:i}=a,o=i||l({slug:r,environment:n,resourceType:"instance-profile"}),c=s(o);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:o,Roles:[P.Ref(e)]}},logicalId:c}}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:a,environment:r,permissions:n,createAccessKey:i=!0}=e,o={},c=[];if(n.s3Buckets&&n.s3Buckets.length>0)c.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...n.s3Buckets,...n.s3Buckets.map((y)=>`${y}/*`)]});if(n.cloudFrontDistributions&&n.cloudFrontDistributions.length>0)c.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:n.cloudFrontDistributions});if(n.ecrRepositories&&n.ecrRepositories.length>0)c.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:n.ecrRepositories}),c.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(n.ecsServices&&n.ecsServices.length>0)c.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:n.ecsServices}),c.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),c.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(n.cloudFormationStacks&&n.cloudFormationStacks.length>0)c.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:n.cloudFormationStacks});if(n.lambdaFunctions&&n.lambdaFunctions.length>0)c.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:n.lambdaFunctions});if(n.secretsManagerSecrets&&n.secretsManagerSecrets.length>0)c.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:n.secretsManagerSecrets});let{policy:u,logicalId:d}=Ee.createPolicy({slug:a,environment:r,policyName:l({slug:a,environment:r,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${a} (${r})`,statements:c});o[d]=u;let{user:m,logicalId:p}=Ee.createUser({slug:a,environment:r,userName:l({slug:a,environment:r,resourceType:"cicd-user"}),managedPolicyArns:[P.Ref(d)]});o[p]=m;let g,h;if(i){let y=Ee.createAccessKey(p,{slug:a,environment:r});g=y.accessKey,h=y.logicalId,o[h]=g}return{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:h,policyLogicalId:d,resources:o}}static createCrossAccountRole(e){let{slug:a,environment:r,trustedAccountIds:n,externalId:i,permissions:o,maxSessionDuration:c=3600}=e,u={},{policy:d,logicalId:m}=Ee.createPolicy({slug:a,environment:r,policyName:l({slug:a,environment:r,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${a} (${r})`,statements:o});u[m]=d;let p=l({slug:a,environment:r,resourceType:"cross-account-role"}),g=s(p),h={};if(i)h.StringEquals={"sts:ExternalId":i};let y={Type:"AWS::IAM::Role",Properties:{RoleName:p,MaxSessionDuration:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:n.map((f)=>`arn:aws:iam::${f}:root`)},Action:"sts:AssumeRole",...Object.keys(h).length>0?{Condition:h}:{}}]},ManagedPolicyArns:[P.Ref(m)],Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Cross-Account Access"}]}};return u[g]=y,{role:y,policy:d,roleLogicalId:g,policyLogicalId:m,resources:u}}static createCliUser(e){let{slug:a,environment:r,permissions:n="readonly"}=e,i={},o=[],c=[];switch(n){case"readonly":c=[Ee.ManagedPolicies.ReadOnlyAccess];break;case"deploy":o=[{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":c=[Ee.ManagedPolicies.AdministratorAccess];break}let u,d;if(o.length>0){let y=Ee.createPolicy({slug:a,environment:r,policyName:l({slug:a,environment:r,resourceType:"cli-policy"}),description:`CLI access policy for ${a} (${r})`,statements:o});u=y.policy,d=y.logicalId,i[d]=u,c=[P.Ref(d)]}let{user:m,logicalId:p}=Ee.createUser({slug:a,environment:r,userName:l({slug:a,environment:r,resourceType:"cli-user"}),managedPolicyArns:c});i[p]=m;let{accessKey:g,logicalId:h}=Ee.createAccessKey(p,{slug:a,environment:r});return i[h]=g,{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:h,policyLogicalId:d,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((a)=>`${a}/*`)}],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 xo{static createRestApi(e){let{slug:a,environment:r,name:n,description:i,endpointType:o="REGIONAL",binaryMediaTypes:c,compressionSize:u}=e,d=n||l({slug:a,environment:r,resourceType:"rest-api"}),m=s(d),p={Type:"AWS::ApiGateway::RestApi",Properties:{Name:d,Description:i||`REST API for ${a} ${r}`,EndpointConfiguration:{Types:[o]},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.BinaryMediaTypes=c;if(u!==void 0)p.Properties.MinimumCompressionSize=u;return{restApi:p,logicalId:m}}static createHttpApi(e){let{slug:a,environment:r,name:n,description:i,corsEnabled:o=!0,corsOrigins:c=["*"],corsMethods:u=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:d=["*"],corsMaxAge:m=86400,corsAllowCredentials:p=!1}=e,g=n||l({slug:a,environment:r,resourceType:"http-api"}),h=s(g),y={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:g,Description:i||`HTTP API for ${a} ${r}`,ProtocolType:"HTTP",Tags:{Name:g,Environment:r}}};if(o)y.Properties.CorsConfiguration={AllowOrigins:c,AllowMethods:u,AllowHeaders:d,MaxAge:m,AllowCredentials:p};return{httpApi:y,logicalId:h}}static createWebSocketApi(e){let{slug:a,environment:r,name:n,description:i}=e,o=n||l({slug:a,environment:r,resourceType:"ws-api"}),c=s(o);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:o,Description:i||`WebSocket API for ${a} ${r}`,ProtocolType:"WEBSOCKET",Tags:{Name:o,Environment:r}}},logicalId:c}}static createDeployment(e,a){let{slug:r,environment:n,description:i}=a,o=l({slug:r,environment:n,resourceType:"api-deployment"}),c=s(o);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:P.Ref(e),Description:i||`Deployment for ${o}`}},logicalId:c}}static createStage(e,a,r){let{slug:n,environment:i,stageName:o,description:c,cacheEnabled:u=!1,cacheSize:d="0.5",variables:m,throttling:p}=r,g=l({slug:n,environment:i,resourceType:"api-stage"}),h=s(g),y={Type:"AWS::ApiGateway::Stage",Properties:{StageName:o||i,RestApiId:P.Ref(e),DeploymentId:P.Ref(a),Description:c,CacheClusterEnabled:u,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:i}]}};if(u)y.Properties.CacheClusterSize=d;if(m)y.Properties.Variables=m;if(p)y.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:p.burstLimit,ThrottlingRateLimit:p.rateLimit}];return{stage:y,logicalId:h}}static createAuthorizer(e,a){let{slug:r,environment:n,name:i,type:o,functionArn:c,identitySource:u,userPoolArns:d,ttl:m=300}=a,p=i||l({slug:r,environment:n,resourceType:"api-authorizer"}),g=s(p),h={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:p,Type:o,RestApiId:P.Ref(e),AuthorizerResultTtlInSeconds:m}};if(o==="TOKEN"||o==="REQUEST"){if(!c)throw Error("Lambda authorizer requires functionArn");h.Properties.AuthorizerUri=c,h.Properties.IdentitySource=u||"method.request.header.Authorization"}if(o==="COGNITO_USER_POOLS"){if(!d||d.length===0)throw Error("Cognito authorizer requires userPoolArns");h.Properties.ProviderARNs=d,h.Properties.IdentitySource=u||"method.request.header.Authorization"}return{authorizer:h,logicalId:g}}static setCors(e,a={}){let{origins:r=["*"],methods:n=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:i=["*"],maxAge:o=86400,allowCredentials:c=!1}=a;return e.Properties.CorsConfiguration={AllowOrigins:r,AllowMethods:n,AllowHeaders:i,MaxAge:o,AllowCredentials:c},e}static addThrottling(e,a=5000,r=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:a,ThrottlingRateLimit:r}),e}static enableCaching(e,a="0.5",r=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=a,!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:r}),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 ke{static createTopic(e){let{slug:a,environment:r,topicName:n,displayName:i,encrypted:o=!1,kmsKeyId:c}=e,u=n||l({slug:a,environment:r,resourceType:"topic"}),d=s(u),m={Type:"AWS::SNS::Topic",Properties:{TopicName:u,DisplayName:i||u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(o&&c)m.Properties.KmsMasterKeyId=c;return{topic:m,logicalId:d}}static subscribe(e,a){let{slug:r,environment:n,protocol:i,endpoint:o,filterPolicy:c,rawMessageDelivery:u=!1}=a,d=l({slug:r,environment:n,resourceType:"subscription"}),m=o.replace(/[^a-zA-Z0-9]/g,""),p=m.length>12?m.slice(-12):m,g=s(`${d}-${i}-${p}`),h={Type:"AWS::SNS::Subscription",Properties:{TopicArn:P.Ref(e),Protocol:i,Endpoint:o,RawMessageDelivery:u}};if(c)h.Properties.FilterPolicy=c;return{subscription:h,logicalId:g}}static subscribeEmail(e,a,r){return ke.subscribe(e,{...r,protocol:"email",endpoint:a})}static subscribeLambda(e,a,r){return ke.subscribe(e,{...r,protocol:"lambda",endpoint:a,rawMessageDelivery:!0})}static subscribeSqs(e,a,r){return ke.subscribe(e,{...r,protocol:"sqs",endpoint:a})}static subscribeHttp(e,a,r){let n=a.startsWith("https://")?"https":"http";return ke.subscribe(e,{...r,protocol:n,endpoint:a})}static subscribeSms(e,a,r){return ke.subscribe(e,{...r,protocol:"sms",endpoint:a})}static setTopicPolicy(e,a){let{slug:r,environment:n,allowedPrincipals:i,allowedServices:o,actions:c="SNS:Publish"}=a,u=l({slug:r,environment:n,resourceType:"topic-policy"}),d=s(u),m={};if(i)m.AWS=i;if(o)m.Service=o;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[P.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:c,Resource:P.Ref(e)}]}}},logicalId:d}}static allowCloudWatchAlarms(e,a){return ke.setTopicPolicy(e,{...a,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,a){return ke.setTopicPolicy(e,{...a,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,a){return ke.setTopicPolicy(e,{...a,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,a){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=a,e}static addInlineSubscription(e,a,r){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:a,Endpoint:r}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,a,r)=>({[e]:[{numeric:[">=",a,"<=",r]}]}),prefix:(e,a)=>({[e]:[{prefix:a}]}),and:(...e)=>Object.assign({},...e),exists:(e,a)=>({[e]:[{exists:a}]})};static UseCases={createAlertTopic:(e)=>ke.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>ke.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>ke.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class Od{static createStateMachine(e){let{slug:a,environment:r,stateMachineName:n,type:i="STANDARD",definition:o,roleArn:c,loggingConfiguration:u,tracingConfiguration:d}=e,m=n||l({slug:a,environment:r,resourceType:"state-machine"}),p=s(m),g,h,y;if(c)y=c;else{let b=l({slug:a,environment:r,resourceType:"state-machine-role"});h=s(b),g={Type:"AWS::IAM::Role",Properties:{RoleName:b,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:b},{Key:"Environment",Value:r}]}},y=P.GetAtt(h,"Arn")}let f={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:m,StateMachineType:i,DefinitionString:JSON.stringify(o),RoleArn:y,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(u)f.Properties.LoggingConfiguration={Level:u.level,IncludeExecutionData:u.includeExecutionData,Destinations:u.destinations?.map((b)=>({CloudWatchLogsLogGroup:{LogGroupArn:b}}))};if(d)f.Properties.TracingConfiguration={Enabled:d.enabled};return{stateMachine:f,logicalId:p,role:g,roleLogicalId:h}}static createLambdaTask(e,a){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:a?.parameters||{"Input.$":"$"}},ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createDynamoDBTask(e,a,r,n){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:a,...r},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createSNSPublishTask(e,a,r){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:a},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSQSSendMessageTask(e,a,r){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:a},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.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,a){return{Type:"Choice",Choices:e,Default:a}}static createParallelState(e,a){return{Type:"Parallel",Branches:e,ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createMapState(e,a){return{Type:"Map",ItemsPath:a?.itemsPath||"$.items",Iterator:e,MaxConcurrency:a?.maxConcurrency,ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,a){return{Type:"Fail",Error:e,Cause:a}}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,a,r,n)=>({ErrorEquals:e,IntervalSeconds:a,MaxAttempts:r,BackoffRate:n})};static CatchPolicies={all:(e,a)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:a||"$.error"}),specific:(e,a,r)=>({ErrorEquals:e,Next:a,ResultPath:r||"$.error"})};static Patterns={sequential:(e,a,r)=>{let n={};return r.forEach((i,o)=>{let c=o===r.length-1;n[i.name]={...i.state,Next:c?void 0:r[o+1].name,End:c}}),{Comment:"Sequential workflow",StartAt:r[0].name,States:n}},fanout:(e,a,r)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:r.map((n)=>n.definition),End:!0}}}),map:(e,a,r,n)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:r,MaxConcurrency:n,End:!0}}}),withErrorHandling:(e,a,r,n)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...r,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:n,Success:{Type:"Succeed"}}})}}class Ti{static createAlarm(e){let{slug:a,environment:r,alarmName:n,metricName:i,namespace:o,statistic:c="Average",period:u=300,evaluationPeriods:d=1,threshold:m,comparisonOperator:p,treatMissingData:g="notBreaching",actionsEnabled:h=!0,alarmActions:y,okActions:f,insufficientDataActions:b,dimensions:v,unit:T,datapointsToAlarm:I}=e,C=n||l({slug:a,environment:r,resourceType:"alarm"}),N=s(C),R={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:C,MetricName:i,Namespace:o,Statistic:c,Period:u,EvaluationPeriods:d,Threshold:m,ComparisonOperator:p,TreatMissingData:g,ActionsEnabled:h}};if(y&&y.length>0)R.Properties.AlarmActions=y;if(f&&f.length>0)R.Properties.OKActions=f;if(b&&b.length>0)R.Properties.InsufficientDataActions=b;if(v)R.Properties.Dimensions=Object.entries(v).map(([k,x])=>({Name:k,Value:x}));if(T)R.Properties.Unit=T;if(I!==void 0)R.Properties.DatapointsToAlarm=I;return{alarm:R,logicalId:N}}static createCompositeAlarm(e){let{slug:a,environment:r,alarmName:n,alarmRule:i,actionsEnabled:o=!0,alarmActions:c,okActions:u,insufficientDataActions:d}=e,m=n||l({slug:a,environment:r,resourceType:"composite-alarm"}),p=s(m),g={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:m,AlarmRule:i,ActionsEnabled:o}};if(c&&c.length>0)g.Properties.AlarmActions=c;if(u&&u.length>0)g.Properties.OKActions=u;if(d&&d.length>0)g.Properties.InsufficientDataActions=d;return{alarm:g,logicalId:p}}static createDashboard(e){let{slug:a,environment:r,dashboardName:n,widgets:i}=e,o=n||l({slug:a,environment:r,resourceType:"dashboard"}),c=s(o),u={widgets:i.map((d)=>({type:d.type,x:d.x,y:d.y,width:d.width,height:d.height,properties:d.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:o,DashboardBody:JSON.stringify(u)}},logicalId:c}}static createLogGroup(e){let{slug:a,environment:r,logGroupName:n,retentionInDays:i,kmsKeyId:o}=e,c=n||l({slug:a,environment:r,resourceType:"log-group"}),u=s(c),d={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:c}};if(i!==void 0)d.Properties.RetentionInDays=i;if(o)d.Properties.KmsKeyId=o;return{logGroup:d,logicalId:u}}static createLogStream(e,a){let{slug:r,environment:n,logStreamName:i}=a,o=i||l({slug:r,environment:n,resourceType:"log-stream"}),c=s(o);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:P.Ref(e),LogStreamName:o}},logicalId:c}}static createMetricFilter(e,a){let{slug:r,environment:n,filterName:i,filterPattern:o,metricTransformations:c}=a,u=i||l({slug:r,environment:n,resourceType:"metric-filter"}),d=s(u);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:P.Ref(e),FilterPattern:o,MetricTransformations:c.map((m)=>({MetricName:m.metricName,MetricNamespace:m.metricNamespace,MetricValue:m.metricValue,DefaultValue:m.defaultValue,Unit:m.unit}))}},logicalId:d}}static AlarmTypes={highCpu:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:i?[i]:void 0}),highMemory:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:i?[i]:void 0}),highDisk:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:i?[i]:void 0}),lambdaErrors:(e,a,r,n=5,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:i?[i]:void 0}),lambdaThrottles:(e,a,r,n=10,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:i?[i]:void 0}),apiGateway5xxErrors:(e,a,r,n=10,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:i?[i]:void 0}),apiGateway4xxErrors:(e,a,r,n=50,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:i?[i]:void 0}),dynamoDBThrottles:(e,a,r,n=5,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:r},alarmActions:i?[i]:void 0}),rdsCpu:(e,a,r,n=80,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:i?[i]:void 0}),rdsFreeStorage:(e,a,r,n=5368709120,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:i?[i]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,a,r,n=100,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:r},alarmActions:i?[i]:void 0}),albUnhealthyTargets:(e,a,r,n,i=1,o)=>({slug:e,environment:a,alarmName:`${e}-${a}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:r,TargetGroup:n},alarmActions:o?[o]:void 0}),sesBounceRate:(e,a,r=5,n)=>({slug:e,environment:a,alarmName:`${e}-${a}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:n?[n]:void 0}),sesComplaintRate:(e,a,r=0.1,n)=>({slug:e,environment:a,alarmName:`${e}-${a}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:n?[n]:void 0}),smsDeliveryFailure:(e,a,r,n=10,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:r},alarmActions:i?[i]:void 0}),smsSpendLimit:(e,a,r=100,n)=>({slug:e,environment:a,alarmName:`${e}-${a}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",alarmActions:n?[n]:void 0}),connectMissedCalls:(e,a,r,n=5,i)=>({slug:e,environment:a,alarmName:`${e}-${a}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:i?[i]:void 0})};static DashboardWidgets={metric:(e,a,r,n,i,o)=>({type:"metric",x:e,y:a,width:r,height:n,properties:{metrics:i,title:o||"Metrics",region:"us-east-1",period:300}}),text:(e,a,r,n,i)=>({type:"text",x:e,y:a,width:r,height:n,properties:{markdown:i}}),log:(e,a,r,n,i,o)=>({type:"log",x:e,y:a,width:r,height:n,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:o||"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,a)=>`{ $.${e} = "${a}" }`,httpStatus:(e)=>`[..., status_code = ${e}, ...]`,http4xx:"[..., status_code = 4*, ...]",http5xx:"[..., status_code = 5*, ...]"};static createApplicationDashboard(e){let{slug:a,environment:r,region:n="us-east-1",components:i={}}=e,o=[],c=0;if(o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:`# ${a.toUpperCase()} Dashboard (${r})`}}),c+=1,i.ec2InstanceIds&&i.ec2InstanceIds.length>0)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## EC2 Instances"}}),c+=1,o.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:n,metrics:i.ec2InstanceIds.map((u)=>["AWS/EC2","CPUUtilization","InstanceId",u]),period:300,stat:"Average"}}),o.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Network Traffic",region:n,metrics:[...i.ec2InstanceIds.flatMap((u)=>[["AWS/EC2","NetworkIn","InstanceId",u,{label:`${u} In`}],["AWS/EC2","NetworkOut","InstanceId",u,{label:`${u} Out`}]])],period:300,stat:"Sum"}}),o.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Status Checks",region:n,metrics:i.ec2InstanceIds.map((u)=>["AWS/EC2","StatusCheckFailed","InstanceId",u]),period:60,stat:"Maximum"}}),c+=6;if(i.lambdaFunctionNames&&i.lambdaFunctionNames.length>0)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Lambda Functions"}}),c+=1,o.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"Invocations",region:n,metrics:i.lambdaFunctionNames.map((u)=>["AWS/Lambda","Invocations","FunctionName",u]),period:300,stat:"Sum"}}),o.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Duration",region:n,metrics:i.lambdaFunctionNames.map((u)=>["AWS/Lambda","Duration","FunctionName",u]),period:300,stat:"Average"}}),o.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Errors",region:n,metrics:i.lambdaFunctionNames.map((u)=>["AWS/Lambda","Errors","FunctionName",u]),period:300,stat:"Sum"}}),c+=6;if(i.ecsClusterName&&i.ecsServiceName)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## ECS Service"}}),c+=1,o.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:n,metrics:[["AWS/ECS","CPUUtilization","ClusterName",i.ecsClusterName,"ServiceName",i.ecsServiceName]],period:300,stat:"Average"}}),o.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Memory Utilization",region:n,metrics:[["AWS/ECS","MemoryUtilization","ClusterName",i.ecsClusterName,"ServiceName",i.ecsServiceName]],period:300,stat:"Average"}}),o.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Running Tasks",region:n,metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",i.ecsClusterName,"ServiceName",i.ecsServiceName]],period:60,stat:"Average"}}),c+=6;if(i.albName)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Application Load Balancer"}}),c+=1,o.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"Request Count",region:n,metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",i.albName]],period:60,stat:"Sum"}}),o.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Response Time",region:n,metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",i.albName]],period:60,stat:"Average"}}),o.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"HTTP Errors",region:n,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"}}),c+=6;if(i.rdsInstanceId)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## RDS Database"}}),c+=1,o.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:n,metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",i.rdsInstanceId]],period:300,stat:"Average"}}),o.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Database Connections",region:n,metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",i.rdsInstanceId]],period:60,stat:"Sum"}}),o.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Free Storage Space",region:n,metrics:[["AWS/RDS","FreeStorageSpace","DBInstanceIdentifier",i.rdsInstanceId]],period:300,stat:"Average"}}),c+=6;if(i.sqsQueueNames&&i.sqsQueueNames.length>0)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## SQS Queues"}}),c+=1,o.push({type:"metric",x:0,y:c,width:12,height:6,properties:{title:"Messages Visible",region:n,metrics:i.sqsQueueNames.map((u)=>["AWS/SQS","ApproximateNumberOfMessagesVisible","QueueName",u]),period:60,stat:"Sum"}}),o.push({type:"metric",x:12,y:c,width:12,height:6,properties:{title:"Message Age",region:n,metrics:i.sqsQueueNames.map((u)=>["AWS/SQS","ApproximateAgeOfOldestMessage","QueueName",u]),period:60,stat:"Maximum"}}),c+=6;if(i.logGroupNames&&i.logGroupNames.length>0)o.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Application Logs"}}),c+=1,o.push({type:"log",x:0,y:c,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:n,title:"Recent Errors and Warnings"}}),c+=6;return Ti.createDashboard({slug:a,environment:r,widgets:o})}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((a,r)=>({type:"metric",x:r%3*8,y:7+Math.floor(r/3)*6,width:8,height:6,properties:{title:`${a} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",a],["AWS/Lambda","Duration","FunctionName",a],["AWS/Lambda","Errors","FunctionName",a]],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:a,namespace:r,threshold:n,comparisonOperator:i="GreaterThanThreshold",evaluationPeriods:o=1,period:c=300,statistic:u="Average",treatMissingData:d="missing"}=e;return{MetricName:a,Namespace:r,Threshold:n,ComparisonOperator:i,EvaluationPeriods:o,Period:c,Statistic:u,TreatMissingData:d}},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 we{static createUserPool(e){let{slug:a,environment:r,userPoolName:n,aliasAttributes:i,autoVerifiedAttributes:o,passwordPolicy:c,mfaConfiguration:u,emailConfiguration:d,smsConfiguration:m,lambdaTriggers:p,userPoolAddOns:g,accountRecoverySetting:h}=e,y=n||l({slug:a,environment:r,resourceType:"user-pool"}),f=s(y),b={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:y,Policies:c?{PasswordPolicy:{MinimumLength:c.minimumLength,RequireLowercase:c.requireLowercase,RequireUppercase:c.requireUppercase,RequireNumbers:c.requireNumbers,RequireSymbols:c.requireSymbols,TemporaryPasswordValidityDays:c.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:u,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(i&&i.length>0)b.Properties.UsernameAttributes=i;if(o&&o.length>0)b.Properties.AutoVerifiedAttributes=o;if(d)b.Properties.EmailConfiguration={EmailSendingAccount:d.emailSendingAccount,From:d.from,ReplyToEmailAddress:d.replyToEmailAddress,SourceArn:d.sourceArn,ConfigurationSet:d.configurationSet};if(m)b.Properties.SmsConfiguration={ExternalId:m.externalId,SnsCallerArn:m.snsCallerArn};if(p)b.Properties.LambdaConfig={PreSignUp:p.preSignUp,PostConfirmation:p.postConfirmation,PreAuthentication:p.preAuthentication,PostAuthentication:p.postAuthentication,CustomMessage:p.customMessage,DefineAuthChallenge:p.defineAuthChallenge,CreateAuthChallenge:p.createAuthChallenge,VerifyAuthChallengeResponse:p.verifyAuthChallengeResponse,PreTokenGeneration:p.preTokenGeneration,UserMigration:p.userMigration};if(g)b.Properties.UserPoolAddOns={AdvancedSecurityMode:g.advancedSecurityMode};if(h)b.Properties.AccountRecoverySetting={RecoveryMechanisms:h.recoveryMechanisms};return{userPool:b,logicalId:f}}static createUserPoolClient(e,a){let{slug:r,environment:n,clientName:i,generateSecret:o=!1,refreshTokenValidity:c,accessTokenValidity:u,idTokenValidity:d,tokenValidityUnits:m,readAttributes:p,writeAttributes:g,explicitAuthFlows:h,preventUserExistenceErrors:y,enableTokenRevocation:f,callbackURLs:b,logoutURLs:T,allowedOAuthFlows:w,allowedOAuthScopes:I,allowedOAuthFlowsUserPoolClient:v,supportedIdentityProviders:N}=a,R=i||l({slug:r,environment:n,resourceType:"user-pool-client"}),k=s(R);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:R,UserPoolId:P.Ref(e),GenerateSecret:o,RefreshTokenValidity:c,AccessTokenValidity:u,IdTokenValidity:d,TokenValidityUnits:m,ReadAttributes:p,WriteAttributes:g,ExplicitAuthFlows:h,PreventUserExistenceErrors:y,EnableTokenRevocation:f,CallbackURLs:b,LogoutURLs:T,AllowedOAuthFlows:w,AllowedOAuthScopes:I,AllowedOAuthFlowsUserPoolClient:v,SupportedIdentityProviders:N}},logicalId:k}}static createUserPoolDomain(e,a){let{slug:r,environment:n,domain:i,customDomainConfig:o}=a,c=l({slug:r,environment:n,resourceType:"user-pool-domain"}),u=s(c);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:i,UserPoolId:P.Ref(e),CustomDomainConfig:o}},logicalId:u}}static createIdentityPool(e){let{slug:a,environment:r,identityPoolName:n,allowUnauthenticatedIdentities:i=!1,cognitoIdentityProviders:o,supportedLoginProviders:c,samlProviderARNs:u,openIdConnectProviderARNs:d}=e,m=n||l({slug:a,environment:r,resourceType:"identity-pool"}),p=s(m);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:m,AllowUnauthenticatedIdentities:i,CognitoIdentityProviders:o,SupportedLoginProviders:c,SamlProviderARNs:u,OpenIdConnectProviderARNs:d}},logicalId:p}}static createIdentityPoolRoleAttachment(e,a){let{slug:r,environment:n,authenticatedRole:i,unauthenticatedRole:o,roleMappings:c}=a,u=l({slug:r,environment:n,resourceType:"identity-pool-role-attachment"}),d=s(u),m={authenticated:i};if(o)m.unauthenticated=o;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:P.Ref(e),Roles:m,RoleMappings:c}},logicalId:d}}static createAuthenticatedRole(e){let{slug:a,environment:r,identityPoolLogicalId:n}=e,i=l({slug:a,environment:r,resourceType:"cognito-authenticated-role"}),o=s(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":P.Ref(n)},"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:r}]}},logicalId:o}}static createUnauthenticatedRole(e){let{slug:a,environment:r,identityPoolLogicalId:n}=e,i=l({slug:a,environment:r,resourceType:"cognito-unauthenticated-role"}),o=s(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":P.Ref(n)},"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:r}]}},logicalId:o}}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,a,r)=>{let{userPool:n,logicalId:i}=we.createUserPool({slug:e,environment:a,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:we.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:o,logicalId:c}=we.createUserPoolClient(i,{slug:e,environment:a,explicitAuthFlows:[...we.AuthFlows.standard],callbackURLs:[r],allowedOAuthFlows:["code"],allowedOAuthScopes:[...we.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:n,poolId:i,client:o,clientId:c}},mobileApp:(e,a)=>{let{userPool:r,logicalId:n}=we.createUserPool({slug:e,environment:a,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:we.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:i,logicalId:o}=we.createUserPoolClient(n,{slug:e,environment:a,explicitAuthFlows:[...we.AuthFlows.standard]}),{identityPool:c,logicalId:u}=we.createIdentityPool({slug:e,environment:a,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:P.Ref(o),ProviderName:P.GetAtt(n,"ProviderName")}]}),{role:d,logicalId:m}=we.createAuthenticatedRole({slug:e,environment:a,identityPoolLogicalId:u}),{attachment:p,logicalId:g}=we.createIdentityPoolRoleAttachment(u,{slug:e,environment:a,authenticatedRole:P.GetAtt(m,"Arn")});return{userPool:r,poolId:n,client:i,clientId:o,identityPool:c,identityPoolId:u,authRole:d,authRoleId:m,attachment:p,attachmentId:g}}}}class Ce{static createApplication(e){let{slug:a,environment:r,applicationName:n,computePlatform:i}=e,o=n||l({slug:a,environment:r,resourceType:"deploy-app"}),c=s(o);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:o,ComputePlatform:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r}]}},logicalId:c}}static createDeploymentGroup(e,a){let{slug:r,environment:n,deploymentGroupName:i,serviceRoleArn:o,autoScalingGroups:c,ec2TagFilters:u,deploymentConfigName:d,autoRollbackConfiguration:m,alarmConfiguration:p,loadBalancerInfo:g,blueGreenDeploymentConfiguration:h}=a,y=i||l({slug:r,environment:n,resourceType:"deploy-group"}),f=s(y);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:P.Ref(e),DeploymentGroupName:y,ServiceRoleArn:o,AutoScalingGroups:c,Ec2TagFilters:u?.map((b)=>({Key:b.key,Value:b.value,Type:b.type})),DeploymentConfigName:d,AutoRollbackConfiguration:m?{Enabled:m.enabled,Events:m.events}:void 0,AlarmConfiguration:p?{Enabled:p.enabled,Alarms:p.alarms?.map((b)=>({Name:b.name})),IgnorePollAlarmFailure:p.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:g?{TargetGroupInfoList:g.targetGroupInfoList?.map((b)=>({Name:b.name})),ElbInfoList:g.elbInfoList?.map((b)=>({Name:b.name}))}:void 0,BlueGreenDeploymentConfiguration:h?{TerminateBlueInstancesOnDeploymentSuccess:h.terminateBlueInstancesOnDeploymentSuccess?{Action:h.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:h.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:h.deploymentReadyOption?{ActionOnTimeout:h.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:h.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:h.greenFleetProvisioningOption?{Action:h.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:n}]}},logicalId:f}}static createDeploymentConfig(e){let{slug:a,environment:r,deploymentConfigName:n,minimumHealthyHosts:i,trafficRoutingConfig:o}=e,c=n||l({slug:a,environment:r,resourceType:"deploy-config"}),u=s(c);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:c,MinimumHealthyHosts:i?{Type:i.type,Value:i.value}:void 0,TrafficRoutingConfig:o?{Type:o.type,TimeBasedCanary:o.timeBasedCanary?{CanaryPercentage:o.timeBasedCanary.canaryPercentage,CanaryInterval:o.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:o.timeBasedLinear?{LinearPercentage:o.timeBasedLinear.linearPercentage,LinearInterval:o.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:u}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(e,a)=>({type:e,value:a})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,a)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:a}}),linear:(e,a)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:a}})};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,a,r,n)=>{let{application:i,logicalId:o}=Ce.createApplication({slug:e,environment:a,computePlatform:"Server"}),{deploymentGroup:c,logicalId:u}=Ce.createDeploymentGroup(o,{slug:e,environment:a,serviceRoleArn:r,autoScalingGroups:n,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:Ce.RollbackConfigs.onFailure()});return{application:i,appId:o,deploymentGroup:c,groupId:u}},lambdaCanaryDeployment:(e,a,r,n=10,i=5)=>{let{application:o,logicalId:c}=Ce.createApplication({slug:e,environment:a,computePlatform:"Lambda"}),{deploymentConfig:u,logicalId:d}=Ce.createDeploymentConfig({slug:e,environment:a,trafficRoutingConfig:Ce.TrafficRouting.canary(n,i)}),{deploymentGroup:m,logicalId:p}=Ce.createDeploymentGroup(c,{slug:e,environment:a,serviceRoleArn:r,deploymentConfigName:P.Ref(d),autoRollbackConfiguration:Ce.RollbackConfigs.onAlarmOrFailure()});return{application:o,appId:c,deploymentConfig:u,configId:d,deploymentGroup:m,groupId:p}},ecsBlueGreenDeployment:(e,a,r,n)=>{let{application:i,logicalId:o}=Ce.createApplication({slug:e,environment:a,computePlatform:"ECS"}),{deploymentGroup:c,logicalId:u}=Ce.createDeploymentGroup(o,{slug:e,environment:a,serviceRoleArn:r,loadBalancerInfo:{targetGroupInfoList:[{name:n}]},blueGreenDeploymentConfiguration:Ce.BlueGreenConfigs.standard(),autoRollbackConfiguration:Ce.RollbackConfigs.onFailure()});return{application:i,appId:o,deploymentGroup:c,groupId:u}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,a=5)=>({type:"canary",canaryPercentage:e,canaryInterval:a}),allAtOnce:()=>({type:"all-at-once"})}}class re{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,a="md5"){let r=at(e);return hn(a).update(r).digest("hex")}static computeShortHash(e){return re.computeFileHash(e).slice(0,8)}static getContentType(e){let a=Oa(e).toLowerCase();return re.ContentTypes[a]||"application/octet-stream"}static shouldHashFile(e,a){return![...re.NoHashPatterns,...a||[]].some((r)=>r.test(e))}static generateHashedFilename(e,a){let r=Oa(e),n=bn(e,r),i=Ma(e);if(i===".")return`${n}.${a}${r}`;return je(i,`${n}.${a}${r}`)}static collectFiles(e,a){let r=[],n=a||e;if(!Rt(e))return r;let i=fn(e,{withFileTypes:!0});for(let o of i){let c=je(e,o.name);if(o.isDirectory())r.push(...re.collectFiles(c,n));else if(o.isFile())r.push(c)}return r}static hashDirectory(e){let{sourceDir:a,outputDir:r,excludePatterns:n=[],hashAlgorithm:i="md5",copyUnhashed:o=!0}=e,c=re.collectFiles(a),u=[],d={};for(let p of c){let g=p.replace(a,"").replace(/^[/\\]/,""),h=re.shouldHashFile(g,n),y=Sn(p),f=h?re.computeFileHash(p,i).slice(0,8):"",b=h?re.generateHashedFilename(g,f):g,T={originalPath:g,hashedPath:b,hash:f,size:y.size,contentType:re.getContentType(p)};if(u.push(T),d[g]=b,r){let w=je(r,b),I=Ma(w);if(!Rt(I)){let{mkdirSync:v}=kr("node:fs");v(I,{recursive:!0})}if(h||o)yn(p,w)}}let m={version:"1.0",timestamp:new Date().toISOString(),assets:u,hashMap:d};if(r){let p=je(r,"asset-manifest.json");nt(p,JSON.stringify(m,null,2))}return m}static getInvalidationPaths(e,a){let r=[];if(!e)return["/*"];let n=e.hashMap,i=a.hashMap;for(let[o,c]of Object.entries(i)){let u=n[o];if(!u||u!==c){if(r.push(`/${o}`),u&&u!==c)r.push(`/${u}`)}}for(let[o,c]of Object.entries(n))if(!i[o])r.push(`/${o}`),r.push(`/${c}`);if(r.length>100)return["/*"];return[...new Set(r)]}static updateHtmlReferences(e){let{htmlDir:a,manifest:r,basePath:n=""}=e,i=re.collectFiles(a).filter((o)=>o.endsWith(".html")||o.endsWith(".htm"));for(let o of i){let c=at(o,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=[new RegExp(`(src|href)=["']${n}/?${re.escapeRegExp(u)}["']`,"g"),new RegExp(`url\\(["']?${n}/?${re.escapeRegExp(u)}["']?\\)`,"g")];for(let p of m)c=c.replace(p,(g)=>g.replace(u,d))}nt(o,c)}}static updateCssReferences(e){let{cssDir:a,manifest:r,basePath:n=""}=e,i=re.collectFiles(a).filter((o)=>o.endsWith(".css"));for(let o of i){let c=at(o,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=new RegExp(`url\\(["']?${n}/?${re.escapeRegExp(u)}["']?\\)`,"g");c=c.replace(m,`url(${n}/${d})`)}nt(o,c)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:a,keyPrefix:r="",excludePatterns:n=[],cacheControl:i={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return re.hashDirectory({sourceDir:a,excludePatterns:n}).assets.map((o)=>{let c=o.hash!=="",u=o.contentType==="text/html",d=i.unhashed||"public, max-age=3600";if(u)d=i.html||"public, max-age=0, must-revalidate";else if(c)d=i.hashed||"public, max-age=31536000, immutable";return{localPath:je(a,o.originalPath),s3Key:r?`${r}/${o.hashedPath}`:o.hashedPath,contentType:o.contentType,cacheControl:d,hash:o.hash}})}static compareManifests(e,a){let r={added:[],removed:[],changed:[],unchanged:[]},n=new Set(Object.keys(e.hashMap)),i=new Set(Object.keys(a.hashMap));for(let o of i)if(!n.has(o))r.added.push(o);for(let o of n)if(!i.has(o))r.removed.push(o);for(let o of i)if(n.has(o))if(e.hashMap[o]!==a.hashMap[o])r.changed.push(o);else r.unchanged.push(o);return r}static loadManifest(e){if(!Rt(e))return null;try{let a=at(e,"utf-8");return JSON.parse(a)}catch{return null}}static saveManifest(e,a){nt(a,JSON.stringify(e,null,2))}}class Ei{static createSecret(e){let{slug:a,environment:r,secretName:n,description:i,secretString:o,kmsKeyId:c,tags:u}=e,d=n||l({slug:a,environment:r,resourceType:"secret"}),m=s(d),p={Type:"AWS::SecretsManager::Secret",Properties:{Name:d,Description:i,SecretString:o,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},...u?Object.entries(u).map(([g,h])=>({Key:g,Value:h})):[]]}};if(c)p.Properties.KmsKeyId=c;return{secret:p,logicalId:m}}static createGeneratedSecret(e){let{slug:a,environment:r,secretName:n,description:i,excludeCharacters:o,excludeLowercase:c,excludeNumbers:u,excludePunctuation:d,excludeUppercase:m,passwordLength:p,requireEachIncludedType:g,kmsKeyId:h,tags:y}=e,f=n||l({slug:a,environment:r,resourceType:"secret"}),b=s(f),T={Type:"AWS::SecretsManager::Secret",Properties:{Name:f,Description:i,GenerateSecretString:{ExcludeCharacters:o,ExcludeLowercase:c,ExcludeNumbers:u,ExcludePunctuation:d,ExcludeUppercase:m,PasswordLength:p||32,RequireEachIncludedType:g!==!1},Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:r},...y?Object.entries(y).map(([w,I])=>({Key:w,Value:I})):[]]}};if(h)T.Properties.KmsKeyId=h;return{secret:T,logicalId:b}}static createDatabaseSecret(e){let{slug:a,environment:r,secretName:n,username:i,dbname:o,engine:c,host:u,port:d,kmsKeyId:m}=e,p=n||l({slug:a,environment:r,resourceType:"db-secret"}),g=s(p),h={username:i};if(o)h.dbname=o;if(c)h.engine=c;if(u)h.host=u;if(d)h.port=d;let y={Type:"AWS::SecretsManager::Secret",Properties:{Name:p,Description:`Database credentials for ${i}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(h),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Type",Value:"database"}]}};if(m)y.Properties.KmsKeyId=m;return{secret:y,logicalId:g}}static attachToDatabase(e){let{slug:a,environment:r,secretId:n,targetId:i,targetType:o}=e,c=l({slug:a,environment:r,resourceType:"secret-attachment"}),u=s(c);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:n,TargetId:i,TargetType:o}},logicalId:u}}static enableRotation(e){let{slug:a,environment:r,secretId:n,rotationLambdaArn:i,automaticallyAfterDays:o,rotationType:c,kmsKeyArn:u,vpcSecurityGroupIds:d,vpcSubnetIds:m}=e,p=l({slug:a,environment:r,resourceType:"secret-rotation"}),g=s(p),h={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:n,RotationRules:{AutomaticallyAfterDays:o||30}}};if(i)h.Properties.RotationLambdaARN=i;else if(c)h.Properties.HostedRotationLambda={RotationType:c,KmsKeyArn:u,VpcSecurityGroupIds:d,VpcSubnetIds:m};return{rotation:h,logicalId:g}}static SecretTypes={apiKey:(e,a,r)=>Ei.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-${r}-api-key`,description:`API key for ${r}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,a,r)=>Ei.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-${r}-oauth-secret`,description:`OAuth client secret for ${r}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,a)=>Ei.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,a)=>Ei.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-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 X{static createParameter(e){let{slug:a,environment:r,parameterName:n,value:i,type:o="String",description:c,tier:u="Standard",tags:d}=e,m=n||l({slug:a,environment:r,resourceType:"parameter"}),p=s(m);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${a}/${r}/${m}`,Type:o,Value:i,Description:c,Tier:u,Tags:{Name:m,Environment:r,...d}}},logicalId:p}}static createString(e,a,r,n,i){return X.createParameter({slug:e,environment:a,parameterName:r,value:n,type:"String",description:i})}static createSecureString(e,a,r,n,i){return X.createParameter({slug:e,environment:a,parameterName:r,value:n,type:"SecureString",description:i})}static createStringList(e,a,r,n,i){return X.createParameter({slug:e,environment:a,parameterName:r,value:n.join(","),type:"StringList",description:i})}static Parameters={databaseUrl:(e,a,r)=>X.createSecureString(e,a,"database-url",r,"Database connection URL"),apiEndpoint:(e,a,r)=>X.createString(e,a,"api-endpoint",r,"API endpoint URL"),appVersion:(e,a,r)=>X.createString(e,a,"app-version",r,"Application version"),featureFlags:(e,a,r)=>X.createStringList(e,a,"feature-flags",r,"Enabled feature flags"),apiKey:(e,a,r,n)=>X.createSecureString(e,a,`${r}-api-key`,n,`API key for ${r}`),oauthCredentials:(e,a,r,n)=>{let i=X.createString(e,a,"oauth-client-id",r,"OAuth client ID"),o=X.createSecureString(e,a,"oauth-client-secret",n,"OAuth client secret");return{clientId:i,clientSecret:o}},smtpCredentials:(e,a,r,n,i,o)=>{let c=X.createString(e,a,"smtp-username",r,"SMTP username"),u=X.createSecureString(e,a,"smtp-password",n,"SMTP password"),d=X.createString(e,a,"smtp-host",i,"SMTP host"),m=X.createString(e,a,"smtp-port",o.toString(),"SMTP port");return{username:c,password:u,host:d,port:m}},redisUrl:(e,a,r)=>X.createSecureString(e,a,"redis-url",r,"Redis connection URL"),s3Bucket:(e,a,r)=>X.createString(e,a,"s3-bucket",r,"S3 bucket name"),cloudFrontDistribution:(e,a,r)=>X.createString(e,a,"cloudfront-distribution-id",r,"CloudFront distribution ID")}}class Ht{static createDomain(e){let{slug:a,environment:r,domainName:n,engineVersion:i="OpenSearch_2.11",instanceType:o="t3.small.search",instanceCount:c=1,volumeSize:u=10,volumeType:d="gp3",dedicatedMaster:m=!1,dedicatedMasterType:p,dedicatedMasterCount:g=3,multiAz:h=!1,availabilityZoneCount:y=2,vpc:f,encryption:b,enforceHttps:T=!0,tlsSecurityPolicy:w="Policy-Min-TLS-1-2-2019-07",advancedSecurity:I,autoSnapshotHour:v=0,autoTune:N=!0,tags:R={}}=e,k=n||l({slug:a,environment:r,resourceType:"search"}),x=s(k);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:k,EngineVersion:i,ClusterConfig:{InstanceType:o,InstanceCount:c,DedicatedMasterEnabled:m,...m&&{DedicatedMasterType:p||o,DedicatedMasterCount:g},ZoneAwarenessEnabled:h,...h&&{ZoneAwarenessConfig:{AvailabilityZoneCount:y}}},EBSOptions:{EBSEnabled:!0,VolumeType:d,VolumeSize:u},DomainEndpointOptions:{EnforceHTTPS:T,TLSSecurityPolicy:w},SnapshotOptions:{AutomatedSnapshotStartHour:v},...f&&{VPCOptions:{SubnetIds:f.subnetIds,SecurityGroupIds:f.securityGroupIds}},...b&&{EncryptionAtRestOptions:{Enabled:b.atRest??!0,...b.kmsKeyId&&{KmsKeyId:b.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:b.nodeToNode??!0}},...I&&{AdvancedSecurityOptions:{Enabled:I.enabled,InternalUserDatabaseEnabled:I.internalUserDatabase??!0,...I.masterUserName&&I.masterUserPassword&&{MasterUserOptions:{MasterUserName:I.masterUserName,MasterUserPassword:I.masterUserPassword}},...I.masterUserArn&&{MasterUserOptions:{MasterUserARN:I.masterUserArn}}}},...N&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:k},{Key:"Environment",Value:r},...Object.entries(R).map(([M,B])=>({Key:M,Value:B}))]}},logicalId:x}}static createAccessPolicy(e,a){let{ipAddresses:r,iamPrincipalArns:n,allowAll:i,vpcEndpoint:o}=a;if(i)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let c=[];if(n&&n.length>0)c.push({Effect:"Allow",Principal:{AWS:n},Action:"es:*",Resource:e});if(r&&r.length>0)c.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e,Condition:{IpAddress:{"aws:SourceIp":r}}});if(o)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};return{Version:"2012-10-17",Statement:c}}static DomainPresets={development:(e,a)=>Ht.createDomain({slug:e,environment:a,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,a,r)=>Ht.createDomain({slug:e,environment:a,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(e,a)=>Ht.createDomain({slug:e,environment:a,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,a,r)=>Ht.createDomain({slug:e,environment:a,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!1},autoTune:!0})};static InstanceTypes={"t3.small.search":"t3.small.search","t3.medium.search":"t3.medium.search","m6g.large.search":"m6g.large.search","m6g.xlarge.search":"m6g.xlarge.search","m6g.2xlarge.search":"m6g.2xlarge.search","r6g.large.search":"r6g.large.search","r6g.xlarge.search":"r6g.xlarge.search","r6g.2xlarge.search":"r6g.2xlarge.search","r6g.4xlarge.search":"r6g.4xlarge.search","c6g.large.search":"c6g.large.search","c6g.xlarge.search":"c6g.xlarge.search","c6g.2xlarge.search":"c6g.2xlarge.search"};static EngineVersions={"OpenSearch_2.11":"OpenSearch_2.11","OpenSearch_2.9":"OpenSearch_2.9","OpenSearch_2.7":"OpenSearch_2.7","OpenSearch_1.3":"OpenSearch_1.3","Elasticsearch_7.10":"Elasticsearch_7.10"}}class Ct{static createDomainRedirectBucket(e){let{slug:a,environment:r,sourceDomain:n,targetDomain:i,protocol:o="https"}=e,c=l({slug:a,environment:r,resourceType:"s3",suffix:"redirect"}),u=s(c),d=s(`${c}-policy`),m={Type:"AWS::S3::Bucket",Properties:{BucketName:n,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:i,Protocol:o}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Domain Redirect"}]}},p={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:P.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[P.Join("",[P.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:m,bucketPolicy:p,logicalId:u,policyLogicalId:d}}static createPathRedirectFunction(e){let{slug:a,environment:r,rules:n}=e,i=l({slug:a,environment:r,resourceType:"cf-redirect"}),o=s(i),c=Ct.generateRedirectFunctionCode(n);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:i,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${a} (${r})`,Runtime:"cloudfront-js-2.0"},FunctionCode:c}},logicalId:o,functionCode:c}}static generateRedirectFunctionCode(e){return`function handler(event) {
|
|
2316
|
+
| limit 50`,region:n,title:"Recent Errors and Warnings"}}),c+=6;return Ti.createDashboard({slug:a,environment:r,widgets:o})}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((a,r)=>({type:"metric",x:r%3*8,y:7+Math.floor(r/3)*6,width:8,height:6,properties:{title:`${a} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",a],["AWS/Lambda","Duration","FunctionName",a],["AWS/Lambda","Errors","FunctionName",a]],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:a,namespace:r,threshold:n,comparisonOperator:i="GreaterThanThreshold",evaluationPeriods:o=1,period:c=300,statistic:u="Average",treatMissingData:d="missing"}=e;return{MetricName:a,Namespace:r,Threshold:n,ComparisonOperator:i,EvaluationPeriods:o,Period:c,Statistic:u,TreatMissingData:d}},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 Ce{static createUserPool(e){let{slug:a,environment:r,userPoolName:n,aliasAttributes:i,autoVerifiedAttributes:o,passwordPolicy:c,mfaConfiguration:u,emailConfiguration:d,smsConfiguration:m,lambdaTriggers:p,userPoolAddOns:g,accountRecoverySetting:h}=e,y=n||l({slug:a,environment:r,resourceType:"user-pool"}),f=s(y),b={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:y,Policies:c?{PasswordPolicy:{MinimumLength:c.minimumLength,RequireLowercase:c.requireLowercase,RequireUppercase:c.requireUppercase,RequireNumbers:c.requireNumbers,RequireSymbols:c.requireSymbols,TemporaryPasswordValidityDays:c.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:u,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(i&&i.length>0)b.Properties.UsernameAttributes=i;if(o&&o.length>0)b.Properties.AutoVerifiedAttributes=o;if(d)b.Properties.EmailConfiguration={EmailSendingAccount:d.emailSendingAccount,From:d.from,ReplyToEmailAddress:d.replyToEmailAddress,SourceArn:d.sourceArn,ConfigurationSet:d.configurationSet};if(m)b.Properties.SmsConfiguration={ExternalId:m.externalId,SnsCallerArn:m.snsCallerArn};if(p)b.Properties.LambdaConfig={PreSignUp:p.preSignUp,PostConfirmation:p.postConfirmation,PreAuthentication:p.preAuthentication,PostAuthentication:p.postAuthentication,CustomMessage:p.customMessage,DefineAuthChallenge:p.defineAuthChallenge,CreateAuthChallenge:p.createAuthChallenge,VerifyAuthChallengeResponse:p.verifyAuthChallengeResponse,PreTokenGeneration:p.preTokenGeneration,UserMigration:p.userMigration};if(g)b.Properties.UserPoolAddOns={AdvancedSecurityMode:g.advancedSecurityMode};if(h)b.Properties.AccountRecoverySetting={RecoveryMechanisms:h.recoveryMechanisms};return{userPool:b,logicalId:f}}static createUserPoolClient(e,a){let{slug:r,environment:n,clientName:i,generateSecret:o=!1,refreshTokenValidity:c,accessTokenValidity:u,idTokenValidity:d,tokenValidityUnits:m,readAttributes:p,writeAttributes:g,explicitAuthFlows:h,preventUserExistenceErrors:y,enableTokenRevocation:f,callbackURLs:b,logoutURLs:v,allowedOAuthFlows:T,allowedOAuthScopes:I,allowedOAuthFlowsUserPoolClient:C,supportedIdentityProviders:N}=a,R=i||l({slug:r,environment:n,resourceType:"user-pool-client"}),k=s(R);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:R,UserPoolId:P.Ref(e),GenerateSecret:o,RefreshTokenValidity:c,AccessTokenValidity:u,IdTokenValidity:d,TokenValidityUnits:m,ReadAttributes:p,WriteAttributes:g,ExplicitAuthFlows:h,PreventUserExistenceErrors:y,EnableTokenRevocation:f,CallbackURLs:b,LogoutURLs:v,AllowedOAuthFlows:T,AllowedOAuthScopes:I,AllowedOAuthFlowsUserPoolClient:C,SupportedIdentityProviders:N}},logicalId:k}}static createUserPoolDomain(e,a){let{slug:r,environment:n,domain:i,customDomainConfig:o}=a,c=l({slug:r,environment:n,resourceType:"user-pool-domain"}),u=s(c);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:i,UserPoolId:P.Ref(e),CustomDomainConfig:o}},logicalId:u}}static createIdentityPool(e){let{slug:a,environment:r,identityPoolName:n,allowUnauthenticatedIdentities:i=!1,cognitoIdentityProviders:o,supportedLoginProviders:c,samlProviderARNs:u,openIdConnectProviderARNs:d}=e,m=n||l({slug:a,environment:r,resourceType:"identity-pool"}),p=s(m);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:m,AllowUnauthenticatedIdentities:i,CognitoIdentityProviders:o,SupportedLoginProviders:c,SamlProviderARNs:u,OpenIdConnectProviderARNs:d}},logicalId:p}}static createIdentityPoolRoleAttachment(e,a){let{slug:r,environment:n,authenticatedRole:i,unauthenticatedRole:o,roleMappings:c}=a,u=l({slug:r,environment:n,resourceType:"identity-pool-role-attachment"}),d=s(u),m={authenticated:i};if(o)m.unauthenticated=o;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:P.Ref(e),Roles:m,RoleMappings:c}},logicalId:d}}static createAuthenticatedRole(e){let{slug:a,environment:r,identityPoolLogicalId:n}=e,i=l({slug:a,environment:r,resourceType:"cognito-authenticated-role"}),o=s(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":P.Ref(n)},"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:r}]}},logicalId:o}}static createUnauthenticatedRole(e){let{slug:a,environment:r,identityPoolLogicalId:n}=e,i=l({slug:a,environment:r,resourceType:"cognito-unauthenticated-role"}),o=s(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":P.Ref(n)},"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:r}]}},logicalId:o}}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,a,r)=>{let{userPool:n,logicalId:i}=Ce.createUserPool({slug:e,environment:a,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Ce.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:o,logicalId:c}=Ce.createUserPoolClient(i,{slug:e,environment:a,explicitAuthFlows:[...Ce.AuthFlows.standard],callbackURLs:[r],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Ce.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:n,poolId:i,client:o,clientId:c}},mobileApp:(e,a)=>{let{userPool:r,logicalId:n}=Ce.createUserPool({slug:e,environment:a,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Ce.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:i,logicalId:o}=Ce.createUserPoolClient(n,{slug:e,environment:a,explicitAuthFlows:[...Ce.AuthFlows.standard]}),{identityPool:c,logicalId:u}=Ce.createIdentityPool({slug:e,environment:a,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:P.Ref(o),ProviderName:P.GetAtt(n,"ProviderName")}]}),{role:d,logicalId:m}=Ce.createAuthenticatedRole({slug:e,environment:a,identityPoolLogicalId:u}),{attachment:p,logicalId:g}=Ce.createIdentityPoolRoleAttachment(u,{slug:e,environment:a,authenticatedRole:P.GetAtt(m,"Arn")});return{userPool:r,poolId:n,client:i,clientId:o,identityPool:c,identityPoolId:u,authRole:d,authRoleId:m,attachment:p,attachmentId:g}}}}class we{static createApplication(e){let{slug:a,environment:r,applicationName:n,computePlatform:i}=e,o=n||l({slug:a,environment:r,resourceType:"deploy-app"}),c=s(o);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:o,ComputePlatform:i,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r}]}},logicalId:c}}static createDeploymentGroup(e,a){let{slug:r,environment:n,deploymentGroupName:i,serviceRoleArn:o,autoScalingGroups:c,ec2TagFilters:u,deploymentConfigName:d,autoRollbackConfiguration:m,alarmConfiguration:p,loadBalancerInfo:g,blueGreenDeploymentConfiguration:h}=a,y=i||l({slug:r,environment:n,resourceType:"deploy-group"}),f=s(y);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:P.Ref(e),DeploymentGroupName:y,ServiceRoleArn:o,AutoScalingGroups:c,Ec2TagFilters:u?.map((b)=>({Key:b.key,Value:b.value,Type:b.type})),DeploymentConfigName:d,AutoRollbackConfiguration:m?{Enabled:m.enabled,Events:m.events}:void 0,AlarmConfiguration:p?{Enabled:p.enabled,Alarms:p.alarms?.map((b)=>({Name:b.name})),IgnorePollAlarmFailure:p.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:g?{TargetGroupInfoList:g.targetGroupInfoList?.map((b)=>({Name:b.name})),ElbInfoList:g.elbInfoList?.map((b)=>({Name:b.name}))}:void 0,BlueGreenDeploymentConfiguration:h?{TerminateBlueInstancesOnDeploymentSuccess:h.terminateBlueInstancesOnDeploymentSuccess?{Action:h.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:h.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:h.deploymentReadyOption?{ActionOnTimeout:h.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:h.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:h.greenFleetProvisioningOption?{Action:h.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:n}]}},logicalId:f}}static createDeploymentConfig(e){let{slug:a,environment:r,deploymentConfigName:n,minimumHealthyHosts:i,trafficRoutingConfig:o}=e,c=n||l({slug:a,environment:r,resourceType:"deploy-config"}),u=s(c);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:c,MinimumHealthyHosts:i?{Type:i.type,Value:i.value}:void 0,TrafficRoutingConfig:o?{Type:o.type,TimeBasedCanary:o.timeBasedCanary?{CanaryPercentage:o.timeBasedCanary.canaryPercentage,CanaryInterval:o.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:o.timeBasedLinear?{LinearPercentage:o.timeBasedLinear.linearPercentage,LinearInterval:o.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:u}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(e,a)=>({type:e,value:a})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,a)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:a}}),linear:(e,a)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:a}})};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,a,r,n)=>{let{application:i,logicalId:o}=we.createApplication({slug:e,environment:a,computePlatform:"Server"}),{deploymentGroup:c,logicalId:u}=we.createDeploymentGroup(o,{slug:e,environment:a,serviceRoleArn:r,autoScalingGroups:n,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:we.RollbackConfigs.onFailure()});return{application:i,appId:o,deploymentGroup:c,groupId:u}},lambdaCanaryDeployment:(e,a,r,n=10,i=5)=>{let{application:o,logicalId:c}=we.createApplication({slug:e,environment:a,computePlatform:"Lambda"}),{deploymentConfig:u,logicalId:d}=we.createDeploymentConfig({slug:e,environment:a,trafficRoutingConfig:we.TrafficRouting.canary(n,i)}),{deploymentGroup:m,logicalId:p}=we.createDeploymentGroup(c,{slug:e,environment:a,serviceRoleArn:r,deploymentConfigName:P.Ref(d),autoRollbackConfiguration:we.RollbackConfigs.onAlarmOrFailure()});return{application:o,appId:c,deploymentConfig:u,configId:d,deploymentGroup:m,groupId:p}},ecsBlueGreenDeployment:(e,a,r,n)=>{let{application:i,logicalId:o}=we.createApplication({slug:e,environment:a,computePlatform:"ECS"}),{deploymentGroup:c,logicalId:u}=we.createDeploymentGroup(o,{slug:e,environment:a,serviceRoleArn:r,loadBalancerInfo:{targetGroupInfoList:[{name:n}]},blueGreenDeploymentConfiguration:we.BlueGreenConfigs.standard(),autoRollbackConfiguration:we.RollbackConfigs.onFailure()});return{application:i,appId:o,deploymentGroup:c,groupId:u}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,a=5)=>({type:"canary",canaryPercentage:e,canaryInterval:a}),allAtOnce:()=>({type:"all-at-once"})}}class re{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,a="md5"){let r=at(e);return hn(a).update(r).digest("hex")}static computeShortHash(e){return re.computeFileHash(e).slice(0,8)}static getContentType(e){let a=Oa(e).toLowerCase();return re.ContentTypes[a]||"application/octet-stream"}static shouldHashFile(e,a){return![...re.NoHashPatterns,...a||[]].some((r)=>r.test(e))}static generateHashedFilename(e,a){let r=Oa(e),n=bn(e,r),i=Ma(e);if(i===".")return`${n}.${a}${r}`;return je(i,`${n}.${a}${r}`)}static collectFiles(e,a){let r=[],n=a||e;if(!Rt(e))return r;let i=fn(e,{withFileTypes:!0});for(let o of i){let c=je(e,o.name);if(o.isDirectory())r.push(...re.collectFiles(c,n));else if(o.isFile())r.push(c)}return r}static hashDirectory(e){let{sourceDir:a,outputDir:r,excludePatterns:n=[],hashAlgorithm:i="md5",copyUnhashed:o=!0}=e,c=re.collectFiles(a),u=[],d={};for(let p of c){let g=p.replace(a,"").replace(/^[/\\]/,""),h=re.shouldHashFile(g,n),y=Sn(p),f=h?re.computeFileHash(p,i).slice(0,8):"",b=h?re.generateHashedFilename(g,f):g,v={originalPath:g,hashedPath:b,hash:f,size:y.size,contentType:re.getContentType(p)};if(u.push(v),d[g]=b,r){let T=je(r,b),I=Ma(T);if(!Rt(I)){let{mkdirSync:C}=kr("node:fs");C(I,{recursive:!0})}if(h||o)yn(p,T)}}let m={version:"1.0",timestamp:new Date().toISOString(),assets:u,hashMap:d};if(r){let p=je(r,"asset-manifest.json");nt(p,JSON.stringify(m,null,2))}return m}static getInvalidationPaths(e,a){let r=[];if(!e)return["/*"];let n=e.hashMap,i=a.hashMap;for(let[o,c]of Object.entries(i)){let u=n[o];if(!u||u!==c){if(r.push(`/${o}`),u&&u!==c)r.push(`/${u}`)}}for(let[o,c]of Object.entries(n))if(!i[o])r.push(`/${o}`),r.push(`/${c}`);if(r.length>100)return["/*"];return[...new Set(r)]}static updateHtmlReferences(e){let{htmlDir:a,manifest:r,basePath:n=""}=e,i=re.collectFiles(a).filter((o)=>o.endsWith(".html")||o.endsWith(".htm"));for(let o of i){let c=at(o,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=[new RegExp(`(src|href)=["']${n}/?${re.escapeRegExp(u)}["']`,"g"),new RegExp(`url\\(["']?${n}/?${re.escapeRegExp(u)}["']?\\)`,"g")];for(let p of m)c=c.replace(p,(g)=>g.replace(u,d))}nt(o,c)}}static updateCssReferences(e){let{cssDir:a,manifest:r,basePath:n=""}=e,i=re.collectFiles(a).filter((o)=>o.endsWith(".css"));for(let o of i){let c=at(o,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=new RegExp(`url\\(["']?${n}/?${re.escapeRegExp(u)}["']?\\)`,"g");c=c.replace(m,`url(${n}/${d})`)}nt(o,c)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:a,keyPrefix:r="",excludePatterns:n=[],cacheControl:i={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return re.hashDirectory({sourceDir:a,excludePatterns:n}).assets.map((o)=>{let c=o.hash!=="",u=o.contentType==="text/html",d=i.unhashed||"public, max-age=3600";if(u)d=i.html||"public, max-age=0, must-revalidate";else if(c)d=i.hashed||"public, max-age=31536000, immutable";return{localPath:je(a,o.originalPath),s3Key:r?`${r}/${o.hashedPath}`:o.hashedPath,contentType:o.contentType,cacheControl:d,hash:o.hash}})}static compareManifests(e,a){let r={added:[],removed:[],changed:[],unchanged:[]},n=new Set(Object.keys(e.hashMap)),i=new Set(Object.keys(a.hashMap));for(let o of i)if(!n.has(o))r.added.push(o);for(let o of n)if(!i.has(o))r.removed.push(o);for(let o of i)if(n.has(o))if(e.hashMap[o]!==a.hashMap[o])r.changed.push(o);else r.unchanged.push(o);return r}static loadManifest(e){if(!Rt(e))return null;try{let a=at(e,"utf-8");return JSON.parse(a)}catch{return null}}static saveManifest(e,a){nt(a,JSON.stringify(e,null,2))}}class Ei{static createSecret(e){let{slug:a,environment:r,secretName:n,description:i,secretString:o,kmsKeyId:c,tags:u}=e,d=n||l({slug:a,environment:r,resourceType:"secret"}),m=s(d),p={Type:"AWS::SecretsManager::Secret",Properties:{Name:d,Description:i,SecretString:o,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},...u?Object.entries(u).map(([g,h])=>({Key:g,Value:h})):[]]}};if(c)p.Properties.KmsKeyId=c;return{secret:p,logicalId:m}}static createGeneratedSecret(e){let{slug:a,environment:r,secretName:n,description:i,excludeCharacters:o,excludeLowercase:c,excludeNumbers:u,excludePunctuation:d,excludeUppercase:m,passwordLength:p,requireEachIncludedType:g,kmsKeyId:h,tags:y}=e,f=n||l({slug:a,environment:r,resourceType:"secret"}),b=s(f),v={Type:"AWS::SecretsManager::Secret",Properties:{Name:f,Description:i,GenerateSecretString:{ExcludeCharacters:o,ExcludeLowercase:c,ExcludeNumbers:u,ExcludePunctuation:d,ExcludeUppercase:m,PasswordLength:p||32,RequireEachIncludedType:g!==!1},Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:r},...y?Object.entries(y).map(([T,I])=>({Key:T,Value:I})):[]]}};if(h)v.Properties.KmsKeyId=h;return{secret:v,logicalId:b}}static createDatabaseSecret(e){let{slug:a,environment:r,secretName:n,username:i,dbname:o,engine:c,host:u,port:d,kmsKeyId:m}=e,p=n||l({slug:a,environment:r,resourceType:"db-secret"}),g=s(p),h={username:i};if(o)h.dbname=o;if(c)h.engine=c;if(u)h.host=u;if(d)h.port=d;let y={Type:"AWS::SecretsManager::Secret",Properties:{Name:p,Description:`Database credentials for ${i}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(h),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Type",Value:"database"}]}};if(m)y.Properties.KmsKeyId=m;return{secret:y,logicalId:g}}static attachToDatabase(e){let{slug:a,environment:r,secretId:n,targetId:i,targetType:o}=e,c=l({slug:a,environment:r,resourceType:"secret-attachment"}),u=s(c);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:n,TargetId:i,TargetType:o}},logicalId:u}}static enableRotation(e){let{slug:a,environment:r,secretId:n,rotationLambdaArn:i,automaticallyAfterDays:o,rotationType:c,kmsKeyArn:u,vpcSecurityGroupIds:d,vpcSubnetIds:m}=e,p=l({slug:a,environment:r,resourceType:"secret-rotation"}),g=s(p),h={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:n,RotationRules:{AutomaticallyAfterDays:o||30}}};if(i)h.Properties.RotationLambdaARN=i;else if(c)h.Properties.HostedRotationLambda={RotationType:c,KmsKeyArn:u,VpcSecurityGroupIds:d,VpcSubnetIds:m};return{rotation:h,logicalId:g}}static SecretTypes={apiKey:(e,a,r)=>Ei.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-${r}-api-key`,description:`API key for ${r}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,a,r)=>Ei.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-${r}-oauth-secret`,description:`OAuth client secret for ${r}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,a)=>Ei.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,a)=>Ei.createGeneratedSecret({slug:e,environment:a,secretName:`${e}-${a}-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 X{static createParameter(e){let{slug:a,environment:r,parameterName:n,value:i,type:o="String",description:c,tier:u="Standard",tags:d}=e,m=n||l({slug:a,environment:r,resourceType:"parameter"}),p=s(m);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${a}/${r}/${m}`,Type:o,Value:i,Description:c,Tier:u,Tags:{Name:m,Environment:r,...d}}},logicalId:p}}static createString(e,a,r,n,i){return X.createParameter({slug:e,environment:a,parameterName:r,value:n,type:"String",description:i})}static createSecureString(e,a,r,n,i){return X.createParameter({slug:e,environment:a,parameterName:r,value:n,type:"SecureString",description:i})}static createStringList(e,a,r,n,i){return X.createParameter({slug:e,environment:a,parameterName:r,value:n.join(","),type:"StringList",description:i})}static Parameters={databaseUrl:(e,a,r)=>X.createSecureString(e,a,"database-url",r,"Database connection URL"),apiEndpoint:(e,a,r)=>X.createString(e,a,"api-endpoint",r,"API endpoint URL"),appVersion:(e,a,r)=>X.createString(e,a,"app-version",r,"Application version"),featureFlags:(e,a,r)=>X.createStringList(e,a,"feature-flags",r,"Enabled feature flags"),apiKey:(e,a,r,n)=>X.createSecureString(e,a,`${r}-api-key`,n,`API key for ${r}`),oauthCredentials:(e,a,r,n)=>{let i=X.createString(e,a,"oauth-client-id",r,"OAuth client ID"),o=X.createSecureString(e,a,"oauth-client-secret",n,"OAuth client secret");return{clientId:i,clientSecret:o}},smtpCredentials:(e,a,r,n,i,o)=>{let c=X.createString(e,a,"smtp-username",r,"SMTP username"),u=X.createSecureString(e,a,"smtp-password",n,"SMTP password"),d=X.createString(e,a,"smtp-host",i,"SMTP host"),m=X.createString(e,a,"smtp-port",o.toString(),"SMTP port");return{username:c,password:u,host:d,port:m}},redisUrl:(e,a,r)=>X.createSecureString(e,a,"redis-url",r,"Redis connection URL"),s3Bucket:(e,a,r)=>X.createString(e,a,"s3-bucket",r,"S3 bucket name"),cloudFrontDistribution:(e,a,r)=>X.createString(e,a,"cloudfront-distribution-id",r,"CloudFront distribution ID")}}class Ht{static createDomain(e){let{slug:a,environment:r,domainName:n,engineVersion:i="OpenSearch_2.11",instanceType:o="t3.small.search",instanceCount:c=1,volumeSize:u=10,volumeType:d="gp3",dedicatedMaster:m=!1,dedicatedMasterType:p,dedicatedMasterCount:g=3,multiAz:h=!1,availabilityZoneCount:y=2,vpc:f,encryption:b,enforceHttps:v=!0,tlsSecurityPolicy:T="Policy-Min-TLS-1-2-2019-07",advancedSecurity:I,autoSnapshotHour:C=0,autoTune:N=!0,tags:R={}}=e,k=n||l({slug:a,environment:r,resourceType:"search"}),x=s(k);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:k,EngineVersion:i,ClusterConfig:{InstanceType:o,InstanceCount:c,DedicatedMasterEnabled:m,...m&&{DedicatedMasterType:p||o,DedicatedMasterCount:g},ZoneAwarenessEnabled:h,...h&&{ZoneAwarenessConfig:{AvailabilityZoneCount:y}}},EBSOptions:{EBSEnabled:!0,VolumeType:d,VolumeSize:u},DomainEndpointOptions:{EnforceHTTPS:v,TLSSecurityPolicy:T},SnapshotOptions:{AutomatedSnapshotStartHour:C},...f&&{VPCOptions:{SubnetIds:f.subnetIds,SecurityGroupIds:f.securityGroupIds}},...b&&{EncryptionAtRestOptions:{Enabled:b.atRest??!0,...b.kmsKeyId&&{KmsKeyId:b.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:b.nodeToNode??!0}},...I&&{AdvancedSecurityOptions:{Enabled:I.enabled,InternalUserDatabaseEnabled:I.internalUserDatabase??!0,...I.masterUserName&&I.masterUserPassword&&{MasterUserOptions:{MasterUserName:I.masterUserName,MasterUserPassword:I.masterUserPassword}},...I.masterUserArn&&{MasterUserOptions:{MasterUserARN:I.masterUserArn}}}},...N&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:k},{Key:"Environment",Value:r},...Object.entries(R).map(([M,B])=>({Key:M,Value:B}))]}},logicalId:x}}static createAccessPolicy(e,a){let{ipAddresses:r,iamPrincipalArns:n,allowAll:i,vpcEndpoint:o}=a;if(i)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let c=[];if(n&&n.length>0)c.push({Effect:"Allow",Principal:{AWS:n},Action:"es:*",Resource:e});if(r&&r.length>0)c.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e,Condition:{IpAddress:{"aws:SourceIp":r}}});if(o)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};return{Version:"2012-10-17",Statement:c}}static DomainPresets={development:(e,a)=>Ht.createDomain({slug:e,environment:a,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,a,r)=>Ht.createDomain({slug:e,environment:a,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(e,a)=>Ht.createDomain({slug:e,environment:a,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,a,r)=>Ht.createDomain({slug:e,environment:a,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:r,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 wt{static createDomainRedirectBucket(e){let{slug:a,environment:r,sourceDomain:n,targetDomain:i,protocol:o="https"}=e,c=l({slug:a,environment:r,resourceType:"s3",suffix:"redirect"}),u=s(c),d=s(`${c}-policy`),m={Type:"AWS::S3::Bucket",Properties:{BucketName:n,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:i,Protocol:o}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Domain Redirect"}]}},p={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:P.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[P.Join("",[P.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:m,bucketPolicy:p,logicalId:u,policyLogicalId:d}}static createPathRedirectFunction(e){let{slug:a,environment:r,rules:n}=e,i=l({slug:a,environment:r,resourceType:"cf-redirect"}),o=s(i),c=wt.generateRedirectFunctionCode(n);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:i,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${a} (${r})`,Runtime:"cloudfront-js-2.0"},FunctionCode:c}},logicalId:o,functionCode:c}}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((a)=>{let r=a.preserveQueryString!==!1,n=a.statusCode||301;return` '${a
|
|
|
2367
2367
|
}
|
|
2368
2368
|
|
|
2369
2369
|
return request;
|
|
2370
|
-
}`}static CommonRedirects={wwwToApex:(e,a="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${e}`,targetDomain:e,protocol:a,preservePath:!0}),apexToWww:(e,a="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:e,targetDomain:`www.${e}`,protocol:a,preservePath:!0}),httpToHttps:(e="/")=>({source:e,target:e,statusCode:301}),addTrailingSlash:(e)=>e.map((a)=>({source:a.endsWith("/")?a.slice(0,-1):a,target:a.endsWith("/")?a:`${a}/`,statusCode:301})),removeTrailingSlash:(e)=>e.map((a)=>({source:a.endsWith("/")&&a!=="/"?a:`${a}/`,target:a.endsWith("/")&&a!=="/"?a.slice(0,-1):a,statusCode:301}))};static Patterns={flattenBlogUrls:(e)=>e.map(({oldPath:a,newPath:r})=>({source:a,target:r,statusCode:301,preserveQueryString:!0})),categoryRename:(e,a)=>[{source:`/${e}`,target:`/${a}`,statusCode:301},{source:`/${e}/`,target:`/${a}/`,statusCode:301}],productSlugChange:(e)=>e.map(({oldSlug:a,newSlug:r})=>({source:`/products/${a}`,target:`/products/${r}`,statusCode:301})),apiVersionRedirect:(e,a,r)=>r.map((n)=>({source:`/api/${e}/${n}`,target:`/api/${a}/${n}`,statusCode:307,preserveQueryString:!0})),gonePages:(e)=>e.map((a)=>({source:a,target:"/410",statusCode:301}))};static createRedirectSetup(e){let{slug:a,environment:r,domainRedirects:n=[],pathRedirects:i=[]}=e,o={},c=[];for(let d of n){let{bucket:m,bucketPolicy:p,logicalId:g,policyLogicalId:h}=Ct.createDomainRedirectBucket({...d,slug:a,environment:r});o[g]=m,o[h]=p,c.push(g)}let u=null;if(i.length>0){let{function:d,logicalId:m}=Ct.createPathRedirectFunction({slug:a,environment:r,rules:i});o[m]=d,u=m}return{resources:o,outputs:{domainRedirectBuckets:c,pathRedirectFunctionLogicalId:u}}}static fromMapping(e,a){return Object.entries(e).map(([r,n])=>({source:r,target:n,statusCode:a?.statusCode||301,preserveQueryString:a?.preserveQueryString??!0}))}static validateRules(e){let a=[],r=[],n=new Set;for(let i of e){if(n.has(i.source))a.push(`Duplicate source path: ${i.source}`);if(n.add(i.source),i.source===i.target)a.push(`Redirect loop detected: ${i.source} -> ${i.target}`);if(!i.target.startsWith("/")&&!i.target.startsWith("http"))r.push(`Target URL should start with / or http: ${i.target}`);if(!i.source||i.source.trim()==="")a.push("Source path cannot be empty");if(!i.target||i.target.trim()==="")a.push("Target path cannot be empty")}for(let i of e){let o=e.find((c)=>c.source===i.target);if(o)r.push(`Potential redirect chain: ${i.source} -> ${i.target} -> ${o.target}`)}return{valid:a.length===0,errors:a,warnings:r}}}class Ae{static generate(e){let a={},{slug:r,environment:n,region:i="us-east-1"}=e,o=Ae.createLambdaExecutionRole(r,n);if(Object.assign(a,o.resources),e.email?.enabled){let c=Ae.generateEmailResources(e,o.roleArn);Object.assign(a,c)}if(e.phone?.enabled){let c=Ae.generatePhoneResources(e,o.roleArn);Object.assign(a,c)}if(e.sms?.enabled){let c=Ae.generateSmsResources(e,o.roleArn);Object.assign(a,c)}return a}static createLambdaExecutionRole(e,a){let r=`${e}-${a}-communication-role`,n=s(r);return{resources:{[n]:{Type:"AWS::IAM::Role",Properties:{RoleName:r,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:P.GetAtt(n,"Arn"),roleName:r}}static generateEmailResources(e,a){let{slug:r,environment:n,email:i}=e;if(!i)return{};let o={},c=`${r}-${n}`,u=`${c}-email-storage`,d=s(u);o[d]={Type:"AWS::S3::Bucket",Properties:{BucketName:u,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 m=s(`${c}-ses-identity`);if(o[m]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:i.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},i.notifications?.bounces||i.notifications?.complaints){let p=s(`${c}-bounce-topic`);o[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-bounces`}};let g=s(`${c}-complaint-topic`);o[g]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-complaints`}}}if(i.server?.enabled){let p=s(`${c}-inbound-email`);o[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:60,MemorySize:256,Code:{ZipFile:Ae.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:u,DOMAIN:i.domain}}}};let g=s(`${c}-outbound-email`);o[g]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:30,MemorySize:256,Code:{ZipFile:Ae.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:u,DOMAIN:i.domain}}}}}if(i.advanced?.analytics){let p=s(`${c}-email-analytics`);o[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 p=s(`${c}-email-scheduler`);o[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:300,MemorySize:256,Code:{ZipFile:Ae.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:u}}}};let g=s(`${c}-email-scheduler-rule`);o[g]={Type:"AWS::Events::Rule",Properties:{Name:`${c}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:P.GetAtt(p,"Arn")}]}}}if(i.advanced?.threading){let p=s(`${c}-email-threading`);o[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:60,MemorySize:256,Code:{ZipFile:Ae.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:u}}}}}if(i.advanced?.rules){let p=s(`${c}-email-rules`);o[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 p=s(`${c}-shared-mailboxes`);o[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 p=s(`${c}-email-search`);o[p]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${c}-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 o}static generatePhoneResources(e,a){let{slug:r,environment:n,phone:i}=e;if(!i)return{};let o={},c=`${r}-${n}`,u=s(`${c}-call-log`);if(o[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 p=s(`${c}-voicemail`);o[p]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let d=s(`${c}-phone-notifications`);o[d]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-phone-notifications`}};let m=s(`${c}-incoming-call`);if(o[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:30,MemorySize:256,Code:{ZipFile:Ae.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${c}-call-log`,NOTIFICATION_TOPIC_ARN:P.Ref(d)}}}},i.voicemail?.enabled){let p=s(`${c}-voicemail-handler`);o[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:i.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:Ae.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${c}-voicemail`,TRANSCRIPTION_ENABLED:String(i.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:P.Ref(d)}}}}}if(i.advanced?.recording){let p=s(`${c}-call-recordings`);o[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 p=s(`${c}-callbacks`);o[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 p=s(`${c}-call-metrics`);o[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return o}static generateSmsResources(e,a){let{slug:r,environment:n,sms:i}=e;if(!i)return{};let o={},c=`${r}-${n}`,u=s(`${c}-pinpoint-app`);o[u]={Type:"AWS::Pinpoint::App",Properties:{Name:`${c}-sms`}};let d=s(`${c}-sms-channel`);o[d]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:P.Ref(u),Enabled:!0,SenderId:i.senderId}};let m=s(`${c}-sms-log`);if(o[m]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 y=s(`${c}-sms-optout`);o[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let p=s(`${c}-sms-notifications`);o[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-sms-notifications`}};let g=s(`${c}-send-sms`);o[g]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:30,MemorySize:256,Code:{ZipFile:Ae.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:P.Ref(u),MESSAGE_LOG_TABLE:`${c}-sms-log`,OPT_OUT_TABLE:i.optOut?.enabled?`${c}-sms-optout`:"",MESSAGE_TYPE:i.messageType||"TRANSACTIONAL"}}}};let h=s(`${c}-receive-sms`);if(o[h]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:30,MemorySize:256,Code:{ZipFile:Ae.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${c}-sms-log`,OPT_OUT_TABLE:i.optOut?.enabled?`${c}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:P.Ref(p)}}}},i.advanced?.campaigns){let y=s(`${c}-sms-campaigns`);o[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(i.advanced?.analytics){let y=s(`${c}-sms-analytics`);o[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 y=s(`${c}-short-links`);o[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 y=s(`${c}-chatbot-sessions`);o[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let f=s(`${c}-chatbot-rules`);o[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(i.advanced?.abTesting){let y=s(`${c}-ab-tests`);o[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(i.advanced?.mms){let y=s(`${c}-mms-media`);o[y]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return o}static InboundEmailCode=`
|
|
2370
|
+
}`}static CommonRedirects={wwwToApex:(e,a="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${e}`,targetDomain:e,protocol:a,preservePath:!0}),apexToWww:(e,a="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:e,targetDomain:`www.${e}`,protocol:a,preservePath:!0}),httpToHttps:(e="/")=>({source:e,target:e,statusCode:301}),addTrailingSlash:(e)=>e.map((a)=>({source:a.endsWith("/")?a.slice(0,-1):a,target:a.endsWith("/")?a:`${a}/`,statusCode:301})),removeTrailingSlash:(e)=>e.map((a)=>({source:a.endsWith("/")&&a!=="/"?a:`${a}/`,target:a.endsWith("/")&&a!=="/"?a.slice(0,-1):a,statusCode:301}))};static Patterns={flattenBlogUrls:(e)=>e.map(({oldPath:a,newPath:r})=>({source:a,target:r,statusCode:301,preserveQueryString:!0})),categoryRename:(e,a)=>[{source:`/${e}`,target:`/${a}`,statusCode:301},{source:`/${e}/`,target:`/${a}/`,statusCode:301}],productSlugChange:(e)=>e.map(({oldSlug:a,newSlug:r})=>({source:`/products/${a}`,target:`/products/${r}`,statusCode:301})),apiVersionRedirect:(e,a,r)=>r.map((n)=>({source:`/api/${e}/${n}`,target:`/api/${a}/${n}`,statusCode:307,preserveQueryString:!0})),gonePages:(e)=>e.map((a)=>({source:a,target:"/410",statusCode:301}))};static createRedirectSetup(e){let{slug:a,environment:r,domainRedirects:n=[],pathRedirects:i=[]}=e,o={},c=[];for(let d of n){let{bucket:m,bucketPolicy:p,logicalId:g,policyLogicalId:h}=wt.createDomainRedirectBucket({...d,slug:a,environment:r});o[g]=m,o[h]=p,c.push(g)}let u=null;if(i.length>0){let{function:d,logicalId:m}=wt.createPathRedirectFunction({slug:a,environment:r,rules:i});o[m]=d,u=m}return{resources:o,outputs:{domainRedirectBuckets:c,pathRedirectFunctionLogicalId:u}}}static fromMapping(e,a){return Object.entries(e).map(([r,n])=>({source:r,target:n,statusCode:a?.statusCode||301,preserveQueryString:a?.preserveQueryString??!0}))}static validateRules(e){let a=[],r=[],n=new Set;for(let i of e){if(n.has(i.source))a.push(`Duplicate source path: ${i.source}`);if(n.add(i.source),i.source===i.target)a.push(`Redirect loop detected: ${i.source} -> ${i.target}`);if(!i.target.startsWith("/")&&!i.target.startsWith("http"))r.push(`Target URL should start with / or http: ${i.target}`);if(!i.source||i.source.trim()==="")a.push("Source path cannot be empty");if(!i.target||i.target.trim()==="")a.push("Target path cannot be empty")}for(let i of e){let o=e.find((c)=>c.source===i.target);if(o)r.push(`Potential redirect chain: ${i.source} -> ${i.target} -> ${o.target}`)}return{valid:a.length===0,errors:a,warnings:r}}}class Ae{static generate(e){let a={},{slug:r,environment:n,region:i="us-east-1"}=e,o=Ae.createLambdaExecutionRole(r,n);if(Object.assign(a,o.resources),e.email?.enabled){let c=Ae.generateEmailResources(e,o.roleArn);Object.assign(a,c)}if(e.phone?.enabled){let c=Ae.generatePhoneResources(e,o.roleArn);Object.assign(a,c)}if(e.sms?.enabled){let c=Ae.generateSmsResources(e,o.roleArn);Object.assign(a,c)}return a}static createLambdaExecutionRole(e,a){let r=`${e}-${a}-communication-role`,n=s(r);return{resources:{[n]:{Type:"AWS::IAM::Role",Properties:{RoleName:r,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:P.GetAtt(n,"Arn"),roleName:r}}static generateEmailResources(e,a){let{slug:r,environment:n,email:i}=e;if(!i)return{};let o={},c=`${r}-${n}`,u=`${c}-email-storage`,d=s(u);o[d]={Type:"AWS::S3::Bucket",Properties:{BucketName:u,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 m=s(`${c}-ses-identity`);if(o[m]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:i.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},i.notifications?.bounces||i.notifications?.complaints){let p=s(`${c}-bounce-topic`);o[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-bounces`}};let g=s(`${c}-complaint-topic`);o[g]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-complaints`}}}if(i.server?.enabled){let p=s(`${c}-inbound-email`);o[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:60,MemorySize:256,Code:{ZipFile:Ae.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:u,DOMAIN:i.domain}}}};let g=s(`${c}-outbound-email`);o[g]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:30,MemorySize:256,Code:{ZipFile:Ae.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:u,DOMAIN:i.domain}}}}}if(i.advanced?.analytics){let p=s(`${c}-email-analytics`);o[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 p=s(`${c}-email-scheduler`);o[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:300,MemorySize:256,Code:{ZipFile:Ae.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:u}}}};let g=s(`${c}-email-scheduler-rule`);o[g]={Type:"AWS::Events::Rule",Properties:{Name:`${c}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:P.GetAtt(p,"Arn")}]}}}if(i.advanced?.threading){let p=s(`${c}-email-threading`);o[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:60,MemorySize:256,Code:{ZipFile:Ae.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:u}}}}}if(i.advanced?.rules){let p=s(`${c}-email-rules`);o[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 p=s(`${c}-shared-mailboxes`);o[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 p=s(`${c}-email-search`);o[p]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${c}-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 o}static generatePhoneResources(e,a){let{slug:r,environment:n,phone:i}=e;if(!i)return{};let o={},c=`${r}-${n}`,u=s(`${c}-call-log`);if(o[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 p=s(`${c}-voicemail`);o[p]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let d=s(`${c}-phone-notifications`);o[d]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-phone-notifications`}};let m=s(`${c}-incoming-call`);if(o[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:30,MemorySize:256,Code:{ZipFile:Ae.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${c}-call-log`,NOTIFICATION_TOPIC_ARN:P.Ref(d)}}}},i.voicemail?.enabled){let p=s(`${c}-voicemail-handler`);o[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:i.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:Ae.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${c}-voicemail`,TRANSCRIPTION_ENABLED:String(i.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:P.Ref(d)}}}}}if(i.advanced?.recording){let p=s(`${c}-call-recordings`);o[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 p=s(`${c}-callbacks`);o[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 p=s(`${c}-call-metrics`);o[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return o}static generateSmsResources(e,a){let{slug:r,environment:n,sms:i}=e;if(!i)return{};let o={},c=`${r}-${n}`,u=s(`${c}-pinpoint-app`);o[u]={Type:"AWS::Pinpoint::App",Properties:{Name:`${c}-sms`}};let d=s(`${c}-sms-channel`);o[d]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:P.Ref(u),Enabled:!0,SenderId:i.senderId}};let m=s(`${c}-sms-log`);if(o[m]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 y=s(`${c}-sms-optout`);o[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let p=s(`${c}-sms-notifications`);o[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-sms-notifications`}};let g=s(`${c}-send-sms`);o[g]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:30,MemorySize:256,Code:{ZipFile:Ae.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:P.Ref(u),MESSAGE_LOG_TABLE:`${c}-sms-log`,OPT_OUT_TABLE:i.optOut?.enabled?`${c}-sms-optout`:"",MESSAGE_TYPE:i.messageType||"TRANSACTIONAL"}}}};let h=s(`${c}-receive-sms`);if(o[h]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:a,Timeout:30,MemorySize:256,Code:{ZipFile:Ae.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${c}-sms-log`,OPT_OUT_TABLE:i.optOut?.enabled?`${c}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:P.Ref(p)}}}},i.advanced?.campaigns){let y=s(`${c}-sms-campaigns`);o[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(i.advanced?.analytics){let y=s(`${c}-sms-analytics`);o[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 y=s(`${c}-short-links`);o[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-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 y=s(`${c}-chatbot-sessions`);o[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let f=s(`${c}-chatbot-rules`);o[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(i.advanced?.abTesting){let y=s(`${c}-ab-tests`);o[y]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(i.advanced?.mms){let y=s(`${c}-mms-media`);o[y]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return o}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) => {
|
|
@@ -2490,10 +2490,10 @@ rpm -U ./amazon-cloudwatch-agent.rpm || true
|
|
|
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:[n||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${r}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:n?{domain:n,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:u==="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:d==="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:`${r}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${r}-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:`${r}-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:[`${r}-app`,`${r}-nginx`,`${r}-workers`]}},security:{certificate:n?{domain:n,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:u==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...d==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function tm(e){let{name:a,slug:r,domain:n,repository:i,phpVersion:o="8.3",size:c="small",database:u=r.replace(/-/g,"_"),databasePassword:d,sslEmail:m,deployStrategy:p="push",provider:g="hetzner"}=e;return{project:{name:a,slug:r,region:"us-east-1"},mode:"server",cloud:{provider:g},environments:{production:{type:"production",domain:n}},infrastructure:{compute:{mode:"server",size:c,runtime:"php",webServer:"nginx",php:{versions:[o],default:o},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:u,username:u,password:d}},sites:{main:{root:".",type:"laravel",domain:n,phpVersion:o,repository:{...i,strategy:p},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:m}}}}}function rm(e){let{name:a,slug:r,domain:n,layers:i,phpVersion:o="8.3",architecture:c="x86_64",memory:u=1024,build:d,deploy:m=["migrate --force"],cache:p="dynamodb",scheduler:g="on",region:h="us-east-1"}=e;return{project:{name:a,slug:r,region:h},mode:"serverless",environments:{production:{type:"production",domain:n,app:{kind:"php",runtime:"provided.al2023",phpVersion:o,architecture:c,layers:i,memory:u,build:d,deploy:m,assets:"public",queues:!0,scheduler:g,cache:{driver:p},domain:n}}}}}function nm(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 Ld=Sc,Md="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function ni(e){let a=e.split(".").filter(Boolean);return a.length<=2?e:a.slice(-2).join(".")}function ii(e){let a=2166136261;for(let r=0;r<e.length;r++)a^=e.charCodeAt(r),a=Math.imul(a,16777619);return a>>>0}var Ud=20000,Bd=12000;function Fd(e){return Ud+ii(e)%Bd}function ar(e,a){let r=ni(e);if(r===e)return`dashboard.${r}`;for(let n of a)if(n===r)return`dashboard.${r}`;return`dashboard.${e}`}function rr(e,a){let r=[],n=e.infrastructure?.dns?.domain;if(n&&!e.cloud?.attachTo)r.push(n);if(a&&e.environments?.[a]?.domain)r.push(e.environments[a].domain);for(let i of Object.values(e.sites??{})){let o=i;if(!o||o.redirect)continue;let c=o.domain;if(typeof c==="string")r.push(c);else if(Array.isArray(c))r.push(...c.filter((u)=>typeof u==="string"))}return r.filter((i)=>i&&!i.startsWith("dashboard."))}function jd(e,a,r){if(r)return r;let n=rr(e,a),i=n[0];if(!i)return null;return ar(i,n)}function Vd(e,a,r){if(r)return[r];let n=rr(e,a),i=[];for(let o of n){let c=ar(o,n);if(!i.includes(c))i.push(c)}return i}function qt(e){return Object.entries(e.sites??{}).some(([a,r])=>{if(!r)return!1;let n=r.root??"";return Nr(a)||n==="ui/dist"||n.endsWith("/ui/dist")||n.endsWith("/dist/ui")})}var Pc="dashboard-";function Nc(e){return Pc+e.replace(/^dashboard\./,"").replace(/\./g,"-")}function Nr(e){return e==="dashboard"||e.startsWith(Pc)}function
|
|
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:[n||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${r}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:n?{domain:n,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:u==="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:d==="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:`${r}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${r}-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:`${r}-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:[`${r}-app`,`${r}-nginx`,`${r}-workers`]}},security:{certificate:n?{domain:n,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:u==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...d==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function tm(e){let{name:a,slug:r,domain:n,repository:i,phpVersion:o="8.3",size:c="small",database:u=r.replace(/-/g,"_"),databasePassword:d,sslEmail:m,deployStrategy:p="push",provider:g="hetzner"}=e;return{project:{name:a,slug:r,region:"us-east-1"},mode:"server",cloud:{provider:g},environments:{production:{type:"production",domain:n}},infrastructure:{compute:{mode:"server",size:c,runtime:"php",webServer:"nginx",php:{versions:[o],default:o},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:u,username:u,password:d}},sites:{main:{root:".",type:"laravel",domain:n,phpVersion:o,repository:{...i,strategy:p},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:m}}}}}function rm(e){let{name:a,slug:r,domain:n,layers:i,phpVersion:o="8.3",architecture:c="x86_64",memory:u=1024,build:d,deploy:m=["migrate --force"],cache:p="dynamodb",scheduler:g="on",region:h="us-east-1"}=e;return{project:{name:a,slug:r,region:h},mode:"serverless",environments:{production:{type:"production",domain:n,app:{kind:"php",runtime:"provided.al2023",phpVersion:o,architecture:c,layers:i,memory:u,build:d,deploy:m,assets:"public",queues:!0,scheduler:g,cache:{driver:p},domain:n}}}}}function nm(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 Ld=Sc,Md="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function ni(e){let a=e.split(".").filter(Boolean);return a.length<=2?e:a.slice(-2).join(".")}function ii(e){let a=2166136261;for(let r=0;r<e.length;r++)a^=e.charCodeAt(r),a=Math.imul(a,16777619);return a>>>0}var Ud=20000,Bd=12000;function Fd(e){return Ud+ii(e)%Bd}function ar(e,a){let r=ni(e);if(r===e)return`dashboard.${r}`;for(let n of a)if(n===r)return`dashboard.${r}`;return`dashboard.${e}`}function rr(e,a){let r=[],n=e.infrastructure?.dns?.domain;if(n&&!e.cloud?.attachTo)r.push(n);if(a&&e.environments?.[a]?.domain)r.push(e.environments[a].domain);for(let i of Object.values(e.sites??{})){let o=i;if(!o||o.redirect)continue;let c=o.domain;if(typeof c==="string")r.push(c);else if(Array.isArray(c))r.push(...c.filter((u)=>typeof u==="string"))}return r.filter((i)=>i&&!i.startsWith("dashboard."))}function jd(e,a,r){if(r)return r;let n=rr(e,a),i=n[0];if(!i)return null;return ar(i,n)}function Vd(e,a,r){if(r)return[r];let n=rr(e,a),i=[];for(let o of n){let c=ar(o,n);if(!i.includes(c))i.push(c)}return i}function qt(e){return Object.entries(e.sites??{}).some(([a,r])=>{if(!r)return!1;let n=r.root??"";return Nr(a)||n==="ui/dist"||n.endsWith("/ui/dist")||n.endsWith("/dist/ui")})}var Pc="dashboard-";function Nc(e){return Pc+e.replace(/^dashboard\./,"").replace(/\./g,"-")}function Nr(e){return e==="dashboard"||e.startsWith(Pc)}function Ci(e,a,r){if(qt(e))return[];if(e.cloud?.attachTo)return[];let n=r.password?{auth:{username:r.username||"admin",password:r.password,realm:r.realm}}:{},i=r.build===!1||r.build===void 0?{}:{build:r.build};if(r.live!==!1){let o=jd(e,a,r.domain);if(!o)return[];let c=r.port??Fd(o),u=e.infrastructure?.appDatabase??e.infrastructure?.compute?.database,d={root:r.uiRoot,deploy:"server",domain:o,preStart:["bun install --production --no-save"],start:`bun ${Md} --box --host 127.0.0.1 --port ${c}`,port:c,cpuWeight:10,ioWeight:10,tasksMax:128,env:{APP_ENV:"production",NODE_ENV:"production",TS_CLOUD_DASHBOARD_TELEMETRY:"1",...u?.password?{TS_CLOUD_DASHBOARD_DB_PASSWORD:u.password}:{}},zeroDowntime:!1,sharedPaths:[Ld],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:Nc(o),site:d}]}return Vd(e,a,r.domain).map((o)=>({name:Nc(o),site:{root:r.uiRoot,deploy:"server",type:"static",domain:o,ssl:{provider:"letsencrypt"},...i,...n}}))}function im(e,a,r){return Ci(e,a,r)[0]??null}function Ut(e,a){let r={...e};for(let n in a){let i=a[n],o=r[n];if(i===void 0)continue;if(Array.isArray(i)&&Array.isArray(o))r[n]=[...o,...i];else if(typeof i==="object"&&i!==null&&!Array.isArray(i)&&typeof o==="object"&&o!==null&&!Array.isArray(o))r[n]=Ut(o,i);else r[n]=i}return r}function Dc(e,a){return Ut(e,a)}function om(...e){return e.reduce((a,r)=>Ut(a,r),{})}function sm(e,a){return(r)=>{let n=e(r);if(typeof a==="function")return Dc(n,a(n,r));return Dc(n,a)}}function cn(e){return{infrastructure:e}}function am(e){return cn({monitoring:e})}function cm(e){return cn({security:e})}function lm(e){return cn({databases:e})}function dm(e){return cn({cache:e})}function um(e){return cn({cdn:e})}function pm(e){return cn({queues:e})}Ye();function zd(){let e=process.env.AWS_ACCESS_KEY_ID,a=process.env.AWS_SECRET_ACCESS_KEY;if(!e||!a)return null;return{accessKeyId:e,secretAccessKey:a,sessionToken:process.env.AWS_SESSION_TOKEN}}function Hd(e){let a=e?.profile||process.env.AWS_PROFILE||"default",r=e?.credentialsFile||sr(ir(),".aws","credentials");if(!nr(r))return null;try{let n=Kt(r,"utf-8");return si(n,a)}catch{return null}}function si(e,a){let r=e.split(`
|
|
2494
2494
|
`),n=null,i,o,c;for(let u of r){let d=u.trim();if(!d||d.startsWith("#")||d.startsWith(";"))continue;let m=d.match(/^\[([^\]]+)\]$/);if(m){if(n===a&&i&&o)return{accessKeyId:i,secretAccessKey:o,sessionToken:c};n=m[1],i=void 0,o=void 0,c=void 0;continue}if(n===a){let[p,...g]=d.split("="),h=g.join("=").trim();switch(p.trim().toLowerCase()){case"aws_access_key_id":i=h;break;case"aws_secret_access_key":o=h;break;case"aws_session_token":c=h;break}}}if(n===a&&i&&o)return{accessKeyId:i,secretAccessKey:o,sessionToken:c};return null}async function qd(e){let a=e?.timeout??1000,r="http://169.254.169.254";try{let n=await ze("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},a);if(!n.ok)return null;let i=await n.text(),o=await ze("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":i}},a);if(!o.ok)return null;let c=(await o.text()).trim(),u=await ze(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${c}`,{headers:{"X-aws-ec2-metadata-token":i}},a);if(!u.ok)return null;let d=await u.json();return{accessKeyId:d.AccessKeyId,secretAccessKey:d.SecretAccessKey,sessionToken:d.Token,expiration:new Date(d.Expiration)}}catch{return null}}async function Wd(e){let a=e?.timeout??1000,r=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,n=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,i=null;if(r)i=`http://169.254.170.2${r}`;else if(n)i=n;if(!i)return null;try{let o={},c=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(c)o.Authorization=c;let u=await ze(i,{headers:o},a);if(!u.ok)return null;let d=await u.json();return{accessKeyId:d.AccessKeyId,secretAccessKey:d.SecretAccessKey,sessionToken:d.Token,expiration:new Date(d.Expiration)}}catch{return null}}async function Gd(e){let a=e?.timeout??5000,r=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,n=process.env.AWS_ROLE_ARN,i=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!r||!n)return null;try{let o=Kt(r,"utf-8").trim(),c=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION||"us-east-1",u=c.startsWith("us-gov")?`https://sts.${c}.amazonaws.com`:c==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${c}.amazonaws.com`,d=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:n,RoleSessionName:i,WebIdentityToken:o}),m=await ze(`${u}/?${d.toString()}`,{method:"POST"},a);if(!m.ok)return null;let p=await m.text(),g=qe(p,"AccessKeyId"),h=qe(p,"SecretAccessKey"),y=qe(p,"SessionToken"),f=qe(p,"Expiration");if(!g||!h)return null;return{accessKeyId:g,secretAccessKey:h,sessionToken:y??void 0,expiration:f?new Date(f):void 0}}catch{return null}}async function Oo(e){let a=zd();if(a)return a;let r=Hd(e);if(r)return r;let n=await Gd(e);if(n)return n;let i=await Wd(e);if(i)return i;let o=await qd(e);if(o)return o;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 mm(e){let a=null,r=null;return async()=>{if(a){if(!a.expiration)return a;let n=300000;if(a.expiration.getTime()-Date.now()>n)return a}if(r)return r;return r=Oo(e).then((n)=>(a=n,r=null,n)).catch((n)=>{throw r=null,n}),r}}async function ze(e,a,r){let n=new AbortController,i=setTimeout(()=>n.abort(),r);try{let o=await fetch(e,{...a,signal:n.signal});return clearTimeout(i),o}catch(o){throw clearTimeout(i),o}}function qe(e,a){let r=new RegExp(`<${a}>([^<]+)</${a}>`),n=e.match(r);return n?n[1]:null}async function pa(e){return Oo({profile:e})}function Kd(e){let a=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(a)return a;let r=sr(ir(),".aws","config");if(nr(r))try{let n=Kt(r,"utf-8"),i=e||process.env.AWS_PROFILE||"default",o=i==="default"?"[default]":`[profile ${i}]`,c=n.split(`
|
|
2495
2495
|
`),u=!1;for(let d of c){let m=d.trim();if(m.startsWith("[")){u=m===o;continue}if(u&&m.startsWith("region")){let[,p]=m.split("=");if(p)return p.trim()}}}catch{}return"us-east-1"}async function Jd(e){let a=e||await Oo(),r=Kd();await Ye();let n=r.startsWith("us-gov")?`https://sts.${r}.amazonaws.com`:r==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${r}.amazonaws.com`,i="Action=GetCallerIdentity&Version=2011-06-15",o=ae({method:"POST",url:n,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...a,service:"sts",region:r}),c=await fetch(o.url,{method:o.method,headers:o.headers,body:o.body});if(!c.ok)throw Error(`Failed to get account ID: ${await c.text()}`);let u=await c.text(),d=qe(u,"Account");if(!d)throw Error("Failed to parse account ID from response");return d}await Ye();class Xd{profile;credentials=null;region;constructor(e="us-east-1",a="default"){this.profile=a,this.region=e}async init(){if(this.credentials=await pa(this.profile),this.credentials.region)this.region=this.credentials.region}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async request(e,a){let r=await this.ensureCredentials(),n={Action:e,Version:"2010-05-15",...Bt(a)},i=new URLSearchParams(n).toString(),o=await(await hi({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:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken})).text();return oi(o)}async createStack(e){let a={StackName:e.stackName};if(e.templateBody)a.TemplateBody=e.templateBody;else if(e.templateURL)a.TemplateURL=e.templateURL;else throw Error("Either templateBody or templateURL must be provided");if(e.parameters)for(let[n,[i,o]]of Object.entries(e.parameters).entries())a[`Parameters.member.${n+1}.ParameterKey`]=i,a[`Parameters.member.${n+1}.ParameterValue`]=o;if(e.capabilities)for(let[n,i]of e.capabilities.entries())a[`Capabilities.member.${n+1}`]=i;if(e.tags)for(let[n,[i,o]]of Object.entries(e.tags).entries())a[`Tags.member.${n+1}.Key`]=i,a[`Tags.member.${n+1}.Value`]=o;if(e.timeoutInMinutes)a.TimeoutInMinutes=e.timeoutInMinutes;if(e.onFailure)a.OnFailure=e.onFailure;let r=await this.request("CreateStack",a);return(r?.CreateStackResult||r?.CreateStackResponse?.CreateStackResult||r)?.StackId}async updateStack(e){let a={StackName:e.stackName};if(e.templateBody)a.TemplateBody=e.templateBody;else if(e.templateURL)a.TemplateURL=e.templateURL;if(e.parameters)for(let[n,[i,o]]of Object.entries(e.parameters).entries())a[`Parameters.member.${n+1}.ParameterKey`]=i,a[`Parameters.member.${n+1}.ParameterValue`]=o;if(e.capabilities)for(let[n,i]of e.capabilities.entries())a[`Capabilities.member.${n+1}`]=i;if(e.tags)for(let[n,[i,o]]of Object.entries(e.tags).entries())a[`Tags.member.${n+1}.Key`]=i,a[`Tags.member.${n+1}.Value`]=o;let r=await this.request("UpdateStack",a);return(r?.UpdateStackResult||r?.UpdateStackResponse?.UpdateStackResult||r)?.StackId}async deleteStack(e){await this.request("DeleteStack",{StackName:e})}async describeStack(e){let a=await this.request("DescribeStacks",{StackName:e}),r=(a?.DescribeStacksResult||a?.DescribeStacksResponse?.DescribeStacksResult||a)?.Stacks?.member,n=Array.isArray(r)?r[0]:r;if(!n)throw Error(`Stack ${e} not found`);return ci(n)}async listStacks(e){let a={};if(e)for(let[n,i]of e.entries())a[`StackStatusFilter.member.${n+1}`]=i;let r=await this.request("ListStacks",a);return li(r)}async describeStackEvents(e){let a=await this.request("DescribeStackEvents",{StackName:e});return ui(a)}async waitForStack(e,a,r){let n=0,i=null;while(n<360){n++;let o=await this.describeStack(e);if(r)try{let c=await this.describeStackEvents(e),u=[];if(i){for(let d of c){if(d.EventId===i)break;u.push(d)}u.reverse()}else if(c.length>0)u=[c[0]];for(let d of u)r(d);if(c.length>0)i=c[0].EventId}catch{}if(o.StackStatus&&a.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,a,r){let n={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[a];if(!n)throw Error(`Unknown waiter: ${a}`);return this.waitForStack(e,n,r)}async createChangeSet(e){let a={StackName:e.stackName,ChangeSetName:e.changeSetName,ChangeSetType:"UPDATE"};if(e.templateBody)a.TemplateBody=e.templateBody;else if(e.templateURL)a.TemplateURL=e.templateURL;if(e.parameters)for(let[r,[n,i]]of Object.entries(e.parameters).entries())a[`Parameters.member.${r+1}.ParameterKey`]=n,a[`Parameters.member.${r+1}.ParameterValue`]=i;if(e.capabilities)for(let[r,n]of e.capabilities.entries())a[`Capabilities.member.${r+1}`]=n;return(await this.request("CreateChangeSet",a)).ChangeSetId}async executeChangeSet(e,a){await this.request("ExecuteChangeSet",{ChangeSetName:e,StackName:a})}async describeStacks(e){let a=typeof e==="string"?e:e.stackName;try{return{Stacks:[await this.describeStack(a)]}}catch{return{Stacks:[]}}}async getStackOutputs(e){let a=await this.request("DescribeStacks",{StackName:e}),r=(a?.DescribeStacksResult||a?.DescribeStacksResponse?.DescribeStacksResult||a)?.Stacks?.member,n=Array.isArray(r)?r[0]:r;if(!n)return{};let i={},o=n.Outputs?.member;if(o){let c=Array.isArray(o)?o:[o];for(let u of c)if(u.OutputKey&&u.OutputValue)i[u.OutputKey]=u.OutputValue}return i}}function Bt(e,a=""){let r={};for(let[n,i]of Object.entries(e)){let o=a?`${a}.${n}`:n;if(Array.isArray(i))i.forEach((c,u)=>{if(typeof c==="object")Object.assign(r,Bt(c,`${o}.${u+1}`));else r[`${o}.${u+1}`]=String(c)});else if(typeof i==="object"&&i!==null)Object.assign(r,Bt(i,o));else if(i!==void 0&&i!==null)r[o]=String(i)}return r}function oi(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function a(n,i,o){let c=1,u=o,d=`<${i}`,m=`</${i}>`;while(u<n.length&&c>0){let p=n.indexOf(d,u),g=n.indexOf(m,u);if(g===-1)return-1;if(p!==-1&&p<g){let h=n[p+d.length];if(h===">"||h===" "||h==="/"){let y=n.indexOf(">",p);if(y!==-1&&n[y-1]==="/")u=y+1;else c++,u=y+1}else u=p+d.length}else{if(c--,c===0)return g;u=g+m.length}}return-1}function r(n,i){while(i<n.length&&/\s/.test(n[i]))i++;if(i>=n.length||n[i]!=="<"){let y=n.indexOf("<",i);if(y===-1)return{value:n.slice(i).trim(),end:n.length};return{value:n.slice(i,y).trim(),end:y}}if(n[i+1]==="/")return{value:void 0,end:i};let o=n.slice(i).match(/^<(\w+)([^>]*?)\/?>/);if(!o)return{value:void 0,end:i+1};let c=o[1];if(o[0].endsWith("/>"))return{value:"",end:i+o[0].length};let u=i+o[0].length,d=`</${c}>`,m=a(n,c,u);if(m===-1)return{value:void 0,end:i+o[0].length};let p=n.slice(u,m).trim();if(!p.includes("<"))return{value:p,end:m+d.length};let g={},h=u;while(h<m){while(h<m&&/\s/.test(n[h]))h++;if(h>=m)break;if(n[h]!=="<"||n[h+1]==="/")break;let y=n.slice(h).match(/^<(\w+)/);if(!y)break;let f=y[1],b=r(n,h);if(b.value===void 0){h++;continue}if(f==="member"||g[f]!==void 0){if(!Array.isArray(g[f]))g[f]=g[f]!==void 0?[g[f]]:[];g[f].push(b.value)}else g[f]=b.value;h=b.end}return{value:g,end:m+d.length}}return r(e,0).value||{}}function ci(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function li(e){let a=(e?.ListStacksResult||e?.ListStacksResponse?.ListStacksResult||e)?.StackSummaries?.member;if(!a)return[];return(Array.isArray(a)?a:[a]).map((r)=>({StackName:r.StackName||"",StackId:r.StackId,StackStatus:r.StackStatus,CreationTime:r.CreationTime,LastUpdatedTime:r.LastUpdatedTime,StackStatusReason:r.StackStatusReason,Description:r.Description}))}function ui(e){let a=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!a)return[];return(Array.isArray(a)?a:[a]).map((r)=>({StackId:r.StackId||"",EventId:r.EventId||"",StackName:r.StackName||"",LogicalResourceId:r.LogicalResourceId||"",PhysicalResourceId:r.PhysicalResourceId,ResourceType:r.ResourceType||"",Timestamp:r.Timestamp||"",ResourceStatus:r.ResourceStatus||"",ResourceStatusReason:r.ResourceStatusReason}))}await Ye();var di=5242880,Nt=5242880,mi=5242880;class kc{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 Oo(this.credentialOptions)}buildUrl(e,a){let r=a?encodeURIComponent(a).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return a?`${this.endpoint}/${e}/${r}`:`${this.endpoint}/${e}`;let n=new URL(this.endpoint);return n.hostname=`${e}.${n.hostname}`,a?`${n.origin}/${r}`:n.origin}async get(e,a,r={}){let n=await this.getCredentials(),i=this.buildUrl(e,a),o={};if(r.range)o.Range=r.range;if(r.ifModifiedSince)o["If-Modified-Since"]=r.ifModifiedSince.toUTCString();if(r.ifMatch)o["If-Match"]=r.ifMatch;if(r.ifNoneMatch)o["If-None-Match"]=r.ifNoneMatch;let c=new URL(i);if(r.responseContentType)c.searchParams.set("response-content-type",r.responseContentType);if(r.responseContentDisposition)c.searchParams.set("response-content-disposition",r.responseContentDisposition);let u=ae({method:"GET",url:c.toString(),headers:o,...n,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok&&d.status!==304){let m=await d.text();throw new Ie(`Failed to get object: ${m}`,d.status,e,a)}return d}async getText(e,a,r={}){return(await this.get(e,a,r)).text()}async getJSON(e,a,r={}){return(await this.get(e,a,r)).json()}async getBuffer(e,a,r={}){return(await this.get(e,a,r)).arrayBuffer()}async put(e,a,r,n={}){let i,o;if(typeof r==="string")i=new TextEncoder().encode(r).length,o=r;else if(r instanceof ArrayBuffer)i=r.byteLength,o=r;else if(r instanceof Uint8Array)i=r.byteLength,o=r;else if(r instanceof Blob)i=r.size,o=r;else return this.uploadMultipart(e,a,r,{...n,partSize:Nt});if(i>mi){let c=fi(o).stream();return this.uploadMultipart(e,a,c,{...n,partSize:Nt})}return this.putSimple(e,a,o,i,n)}async putSimple(e,a,r,n,i){let o=await this.getCredentials(),c=this.buildUrl(e,a),u={"Content-Length":String(n),"Content-Type":i.contentType||_a(a)};if(i.contentEncoding)u["Content-Encoding"]=i.contentEncoding;if(i.cacheControl)u["Cache-Control"]=i.cacheControl;if(i.contentDisposition)u["Content-Disposition"]=i.contentDisposition;if(i.storageClass)u["x-amz-storage-class"]=i.storageClass;if(i.serverSideEncryption)u["x-amz-server-side-encryption"]=i.serverSideEncryption;if(i.acl)u["x-amz-acl"]=i.acl;if(i.tagging)u["x-amz-tagging"]=i.tagging;if(i.metadata)for(let[g,h]of Object.entries(i.metadata))u[`x-amz-meta-${g.toLowerCase()}`]=h;let d;if(typeof r==="string")d=r;else if(r instanceof Blob)d=await r.text();else d=new TextDecoder().decode(r instanceof ArrayBuffer?new Uint8Array(r):r);let m=ae({method:"PUT",url:c,headers:u,body:d,...o,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:r});if(!p.ok){let g=await p.text();throw new Ie(`Failed to put object: ${g}`,p.status,e,a)}return{etag:(p.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,a){let r=await this.getCredentials(),n=this.buildUrl(e,a),i=ae({method:"DELETE",url:n,...r,service:"s3",region:this.region}),o=await fetch(i.url,{method:i.method,headers:i.headers});if(!o.ok&&o.status!==204){let c=await o.text();throw new Ie(`Failed to delete object: ${c}`,o.status,e,a)}}async deleteMany(e,a){let r=await this.getCredentials(),n=`${this.buildUrl(e)}?delete`,i=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${a.map((y)=>`<Object><Key>${gi(y)}</Key></Object>`).join("")}</Delete>`,o=ae({method:"POST",url:n,headers:{"Content-Type":"application/xml"},body:i,...r,service:"s3",region:this.region}),c=await fetch(o.url,{method:o.method,headers:o.headers,body:i});if(!c.ok){let y=await c.text();throw new Ie(`Failed to delete objects: ${y}`,c.status,e)}let u=await c.text(),d=[],m=[],p=/<Deleted><Key>([^<]+)<\/Key>/g,g;while((g=p.exec(u))!==null)d.push(g[1]);let h=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((g=h.exec(u))!==null)m.push({key:g[1],error:`${g[2]}: ${g[3]}`});return{deleted:d,errors:m}}async list(e,a={}){let r=await this.getCredentials(),n=new URL(this.buildUrl(e));if(n.searchParams.set("list-type","2"),a.prefix)n.searchParams.set("prefix",a.prefix);if(a.delimiter)n.searchParams.set("delimiter",a.delimiter);if(a.maxKeys)n.searchParams.set("max-keys",String(a.maxKeys));if(a.continuationToken)n.searchParams.set("continuation-token",a.continuationToken);if(a.startAfter)n.searchParams.set("start-after",a.startAfter);let i=ae({method:"GET",url:n.toString(),...r,service:"s3",region:this.region}),o=await fetch(i.url,{method:i.method,headers:i.headers});if(!o.ok){let u=await o.text();throw new Ie(`Failed to list objects: ${u}`,o.status,e)}let c=await o.text();return pi(c)}async*listAll(e,a={}){let r;do{let n=await this.list(e,{...a,continuationToken:r});for(let i of n.contents)yield i;r=n.nextContinuationToken}while(r)}async head(e,a){let r=await this.getCredentials(),n=this.buildUrl(e,a),i=ae({method:"HEAD",url:n,...r,service:"s3",region:this.region}),o=await fetch(i.url,{method:i.method,headers:i.headers});if(o.status===404)return null;if(!o.ok){let u=await o.text();throw new Ie(`Failed to head object: ${u}`,o.status,e,a)}let c={};return o.headers.forEach((u,d)=>{if(d.toLowerCase().startsWith("x-amz-meta-"))c[d.slice(11)]=u}),{contentLength:Number(o.headers.get("Content-Length")||0),contentType:o.headers.get("Content-Type")||"application/octet-stream",etag:(o.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(o.headers.get("Last-Modified")||0),metadata:c,storageClass:o.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:o.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,a){return await this.head(e,a)!==null}async copy(e,a,r,n,i={}){let o=await this.getCredentials(),c=this.buildUrl(r,n),u={"x-amz-copy-source":`/${e}/${encodeURIComponent(a)}`};if(i.metadataDirective)u["x-amz-metadata-directive"]=i.metadataDirective;if(i.contentType)u["Content-Type"]=i.contentType;if(i.storageClass)u["x-amz-storage-class"]=i.storageClass;if(i.acl)u["x-amz-acl"]=i.acl;if(i.metadata)for(let[g,h]of Object.entries(i.metadata))u[`x-amz-meta-${g.toLowerCase()}`]=h;let d=ae({method:"PUT",url:c,headers:u,...o,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers});if(!m.ok){let g=await m.text();throw new Ie(`Failed to copy object: ${g}`,m.status,r,n)}let p=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:p?p[1]:""}}async getPresignedUrl(e,a,r={}){let n=await this.getCredentials(),i=this.buildUrl(e,a);return Nd({url:i,method:r.method||"GET",expiresIn:r.expiresIn||3600,...n,service:"s3",region:this.region})}async uploadMultipart(e,a,r,n={}){let i=await this.getCredentials(),o=Math.max(n.partSize||Nt,di),c,u;if(r instanceof ReadableStream)c=r;else if(r instanceof Blob)c=r.stream(),u=r.size;else{let p=new Blob([r]);c=p.stream(),u=p.size}let{uploadId:d,baseUrl:m}=await this.initiateMultipartUpload(e,a,n);try{let p=await this.uploadParts(e,a,m,d,c,o,i,u,n.concurrency||4,n.onProgress);return await this.completeMultipartUpload(e,a,m,d,p)}catch(p){throw await this.abortMultipartUpload(e,a,d,m).catch(()=>{}),p}}async initiateMultipartUpload(e,a,r){let n=await this.getCredentials(),i=this.buildUrl(e,a),o=`${i}?uploads`,c={"Content-Type":r.contentType||_a(a)};if(r.storageClass)c["x-amz-storage-class"]=r.storageClass;if(r.serverSideEncryption)c["x-amz-server-side-encryption"]=r.serverSideEncryption;if(r.acl)c["x-amz-acl"]=r.acl;if(r.metadata)for(let[g,h]of Object.entries(r.metadata))c[`x-amz-meta-${g.toLowerCase()}`]=h;let u=ae({method:"POST",url:o,headers:c,...n,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok){let g=await d.text();throw new Ie(`Failed to initiate multipart upload: ${g}`,d.status,e,a)}let m=(await d.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!m)throw new Ie("Failed to parse upload ID from response",0,e,a);let p=i;if(d.url)try{let g=new URL(d.url);g.search="",p=g.toString()}catch{}return{uploadId:m[1],baseUrl:p}}async uploadParts(e,a,r,n,i,o,c,u,d,m){let p=[],g=i.getReader(),h=1,y=new Uint8Array(0),f=0,b=u?Math.ceil(u/o):void 0,T=new Map,w=async(v,N)=>{let R=`${r}?partNumber=${N}&uploadId=${encodeURIComponent(n)}`,k={"Content-Length":String(v.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},x=ae({method:"PUT",url:R,headers:k,...c,service:"s3",region:this.region}),M=await fetch(x.url,{method:x.method,headers:x.headers,body:v,redirect:"error"});if(!M.ok){let _=await M.text();throw new Ie(`Failed to upload part ${N}: ${_}`,M.status,e,a)}let B=(M.headers.get("ETag")||"").replace(/"/g,"");if(!B)throw new Ie(`Missing ETag for part ${N}`,M.status,e,a);return{partNumber:N,etag:B}},I=async()=>{let v=await Promise.race(T.values());T.delete(v.partNumber),p.push(v)};while(!0){let{done:v,value:N}=await g.read();if(N){let R=new Uint8Array(y.length+N.length);R.set(y),R.set(N,y.length),y=R}while(y.length>=o||v&&y.length>0){let R=y.slice(0,o);y=y.slice(o);let k=h++;if(T.size>=d)await I();if(T.set(k,w(R,k)),f+=R.byteLength,m)m({loaded:f,total:u||f,part:k,totalParts:b||k})}if(v)break}while(T.size>0)await I();return p.sort((v,N)=>v.partNumber-N.partNumber),p}async completeMultipartUpload(e,a,r,n,i){let o=await this.getCredentials(),c=`${r}?uploadId=${encodeURIComponent(n)}`,u=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${i.map((g)=>`<Part><PartNumber>${g.partNumber}</PartNumber><ETag>"${g.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,d=ae({method:"POST",url:c,headers:{"Content-Type":"application/xml"},body:u,...o,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers,body:u});if(!m.ok){let g=await m.text();throw new Ie(`Failed to complete multipart upload: ${g}`,m.status,e,a)}let p=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:p?p[1]:""}}async abortMultipartUpload(e,a,r,n){let i=await this.getCredentials(),o=`${n??this.buildUrl(e,a)}?uploadId=${encodeURIComponent(r)}`,c=ae({method:"DELETE",url:o,...i,service:"s3",region:this.region});await fetch(c.url,{method:c.method,headers:c.headers})}async emptyAndDeleteBucket(e){let a=[];for await(let o of this.listAll(e,{}))if(a.push(o.key),a.length>=1000)await this.deleteMany(e,a),a=[];if(a.length>0)await this.deleteMany(e,a);let r=await this.getCredentials(),n=this.buildUrl(e),i=ae({method:"DELETE",url:n,...r,service:"s3",region:this.region});await fetch(i.url,{method:i.method,headers:i.headers})}}class Ie extends Error{statusCode;bucket;key;constructor(e,a,r,n){super(e);this.statusCode=a,this.bucket=r,this.key=n,this.name="S3Error"}}function pi(e){let a=[],r=[],n=/<Contents>([\s\S]*?)<\/Contents>/g,i;while((i=n.exec(e))!==null){let c=i[1];a.push({key:z(c,"Key")||"",lastModified:new Date(z(c,"LastModified")||0),etag:(z(c,"ETag")||"").replace(/"/g,""),size:Number(z(c,"Size")||0),storageClass:z(c,"StorageClass")||"STANDARD"})}let o=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((i=o.exec(e))!==null)r.push(i[1]);return{contents:a,commonPrefixes:r,isTruncated:z(e,"IsTruncated")==="true",continuationToken:z(e,"ContinuationToken")||void 0,nextContinuationToken:z(e,"NextContinuationToken")||void 0,keyCount:Number(z(e,"KeyCount")||0),maxKeys:Number(z(e,"MaxKeys")||1000),prefix:z(e,"Prefix")||void 0,delimiter:z(e,"Delimiter")||void 0}}function z(e,a){let r=new RegExp(`<${a}>([^<]*)</${a}>`),n=e.match(r);return n?n[1]:null}function gi(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function _a(e){let a=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"}[a||""]||"application/octet-stream"}function fi(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function gm(e){return new kc(e)}await Ye();class Qd{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await pa(this.profile)}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async createInvalidation(e){let a=await this.ensureCredentials(),r=e.callerReference||`invalidation-${Date.now()}`,n=`<?xml version="1.0" encoding="UTF-8"?>
|
|
2496
|
+
Reason: ${o.StackStatusReason||"Unknown"}`);await new Promise((c)=>setTimeout(c,5000))}throw Error(`Timeout waiting for stack ${e} to complete`)}async waitForStackWithProgress(e,a,r){let n={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[a];if(!n)throw Error(`Unknown waiter: ${a}`);return this.waitForStack(e,n,r)}async createChangeSet(e){let a={StackName:e.stackName,ChangeSetName:e.changeSetName,ChangeSetType:"UPDATE"};if(e.templateBody)a.TemplateBody=e.templateBody;else if(e.templateURL)a.TemplateURL=e.templateURL;if(e.parameters)for(let[r,[n,i]]of Object.entries(e.parameters).entries())a[`Parameters.member.${r+1}.ParameterKey`]=n,a[`Parameters.member.${r+1}.ParameterValue`]=i;if(e.capabilities)for(let[r,n]of e.capabilities.entries())a[`Capabilities.member.${r+1}`]=n;return(await this.request("CreateChangeSet",a)).ChangeSetId}async executeChangeSet(e,a){await this.request("ExecuteChangeSet",{ChangeSetName:e,StackName:a})}async describeStacks(e){let a=typeof e==="string"?e:e.stackName;try{return{Stacks:[await this.describeStack(a)]}}catch{return{Stacks:[]}}}async getStackOutputs(e){let a=await this.request("DescribeStacks",{StackName:e}),r=(a?.DescribeStacksResult||a?.DescribeStacksResponse?.DescribeStacksResult||a)?.Stacks?.member,n=Array.isArray(r)?r[0]:r;if(!n)return{};let i={},o=n.Outputs?.member;if(o){let c=Array.isArray(o)?o:[o];for(let u of c)if(u.OutputKey&&u.OutputValue)i[u.OutputKey]=u.OutputValue}return i}}function Bt(e,a=""){let r={};for(let[n,i]of Object.entries(e)){let o=a?`${a}.${n}`:n;if(Array.isArray(i))i.forEach((c,u)=>{if(typeof c==="object")Object.assign(r,Bt(c,`${o}.${u+1}`));else r[`${o}.${u+1}`]=String(c)});else if(typeof i==="object"&&i!==null)Object.assign(r,Bt(i,o));else if(i!==void 0&&i!==null)r[o]=String(i)}return r}function oi(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function a(n,i,o){let c=1,u=o,d=`<${i}`,m=`</${i}>`;while(u<n.length&&c>0){let p=n.indexOf(d,u),g=n.indexOf(m,u);if(g===-1)return-1;if(p!==-1&&p<g){let h=n[p+d.length];if(h===">"||h===" "||h==="/"){let y=n.indexOf(">",p);if(y!==-1&&n[y-1]==="/")u=y+1;else c++,u=y+1}else u=p+d.length}else{if(c--,c===0)return g;u=g+m.length}}return-1}function r(n,i){while(i<n.length&&/\s/.test(n[i]))i++;if(i>=n.length||n[i]!=="<"){let y=n.indexOf("<",i);if(y===-1)return{value:n.slice(i).trim(),end:n.length};return{value:n.slice(i,y).trim(),end:y}}if(n[i+1]==="/")return{value:void 0,end:i};let o=n.slice(i).match(/^<(\w+)([^>]*?)\/?>/);if(!o)return{value:void 0,end:i+1};let c=o[1];if(o[0].endsWith("/>"))return{value:"",end:i+o[0].length};let u=i+o[0].length,d=`</${c}>`,m=a(n,c,u);if(m===-1)return{value:void 0,end:i+o[0].length};let p=n.slice(u,m).trim();if(!p.includes("<"))return{value:p,end:m+d.length};let g={},h=u;while(h<m){while(h<m&&/\s/.test(n[h]))h++;if(h>=m)break;if(n[h]!=="<"||n[h+1]==="/")break;let y=n.slice(h).match(/^<(\w+)/);if(!y)break;let f=y[1],b=r(n,h);if(b.value===void 0){h++;continue}if(f==="member"||g[f]!==void 0){if(!Array.isArray(g[f]))g[f]=g[f]!==void 0?[g[f]]:[];g[f].push(b.value)}else g[f]=b.value;h=b.end}return{value:g,end:m+d.length}}return r(e,0).value||{}}function ci(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function li(e){let a=(e?.ListStacksResult||e?.ListStacksResponse?.ListStacksResult||e)?.StackSummaries?.member;if(!a)return[];return(Array.isArray(a)?a:[a]).map((r)=>({StackName:r.StackName||"",StackId:r.StackId,StackStatus:r.StackStatus,CreationTime:r.CreationTime,LastUpdatedTime:r.LastUpdatedTime,StackStatusReason:r.StackStatusReason,Description:r.Description}))}function ui(e){let a=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!a)return[];return(Array.isArray(a)?a:[a]).map((r)=>({StackId:r.StackId||"",EventId:r.EventId||"",StackName:r.StackName||"",LogicalResourceId:r.LogicalResourceId||"",PhysicalResourceId:r.PhysicalResourceId,ResourceType:r.ResourceType||"",Timestamp:r.Timestamp||"",ResourceStatus:r.ResourceStatus||"",ResourceStatusReason:r.ResourceStatusReason}))}await Ye();var di=5242880,Nt=5242880,mi=5242880;class kc{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 Oo(this.credentialOptions)}buildUrl(e,a){let r=a?encodeURIComponent(a).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return a?`${this.endpoint}/${e}/${r}`:`${this.endpoint}/${e}`;let n=new URL(this.endpoint);return n.hostname=`${e}.${n.hostname}`,a?`${n.origin}/${r}`:n.origin}async get(e,a,r={}){let n=await this.getCredentials(),i=this.buildUrl(e,a),o={};if(r.range)o.Range=r.range;if(r.ifModifiedSince)o["If-Modified-Since"]=r.ifModifiedSince.toUTCString();if(r.ifMatch)o["If-Match"]=r.ifMatch;if(r.ifNoneMatch)o["If-None-Match"]=r.ifNoneMatch;let c=new URL(i);if(r.responseContentType)c.searchParams.set("response-content-type",r.responseContentType);if(r.responseContentDisposition)c.searchParams.set("response-content-disposition",r.responseContentDisposition);let u=ae({method:"GET",url:c.toString(),headers:o,...n,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok&&d.status!==304){let m=await d.text();throw new Ie(`Failed to get object: ${m}`,d.status,e,a)}return d}async getText(e,a,r={}){return(await this.get(e,a,r)).text()}async getJSON(e,a,r={}){return(await this.get(e,a,r)).json()}async getBuffer(e,a,r={}){return(await this.get(e,a,r)).arrayBuffer()}async put(e,a,r,n={}){let i,o;if(typeof r==="string")i=new TextEncoder().encode(r).length,o=r;else if(r instanceof ArrayBuffer)i=r.byteLength,o=r;else if(r instanceof Uint8Array)i=r.byteLength,o=r;else if(r instanceof Blob)i=r.size,o=r;else return this.uploadMultipart(e,a,r,{...n,partSize:Nt});if(i>mi){let c=fi(o).stream();return this.uploadMultipart(e,a,c,{...n,partSize:Nt})}return this.putSimple(e,a,o,i,n)}async putSimple(e,a,r,n,i){let o=await this.getCredentials(),c=this.buildUrl(e,a),u={"Content-Length":String(n),"Content-Type":i.contentType||_a(a)};if(i.contentEncoding)u["Content-Encoding"]=i.contentEncoding;if(i.cacheControl)u["Cache-Control"]=i.cacheControl;if(i.contentDisposition)u["Content-Disposition"]=i.contentDisposition;if(i.storageClass)u["x-amz-storage-class"]=i.storageClass;if(i.serverSideEncryption)u["x-amz-server-side-encryption"]=i.serverSideEncryption;if(i.acl)u["x-amz-acl"]=i.acl;if(i.tagging)u["x-amz-tagging"]=i.tagging;if(i.metadata)for(let[g,h]of Object.entries(i.metadata))u[`x-amz-meta-${g.toLowerCase()}`]=h;let d;if(typeof r==="string")d=r;else if(r instanceof Blob)d=await r.text();else d=new TextDecoder().decode(r instanceof ArrayBuffer?new Uint8Array(r):r);let m=ae({method:"PUT",url:c,headers:u,body:d,...o,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:r});if(!p.ok){let g=await p.text();throw new Ie(`Failed to put object: ${g}`,p.status,e,a)}return{etag:(p.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,a){let r=await this.getCredentials(),n=this.buildUrl(e,a),i=ae({method:"DELETE",url:n,...r,service:"s3",region:this.region}),o=await fetch(i.url,{method:i.method,headers:i.headers});if(!o.ok&&o.status!==204){let c=await o.text();throw new Ie(`Failed to delete object: ${c}`,o.status,e,a)}}async deleteMany(e,a){let r=await this.getCredentials(),n=`${this.buildUrl(e)}?delete`,i=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${a.map((y)=>`<Object><Key>${gi(y)}</Key></Object>`).join("")}</Delete>`,o=ae({method:"POST",url:n,headers:{"Content-Type":"application/xml"},body:i,...r,service:"s3",region:this.region}),c=await fetch(o.url,{method:o.method,headers:o.headers,body:i});if(!c.ok){let y=await c.text();throw new Ie(`Failed to delete objects: ${y}`,c.status,e)}let u=await c.text(),d=[],m=[],p=/<Deleted><Key>([^<]+)<\/Key>/g,g;while((g=p.exec(u))!==null)d.push(g[1]);let h=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((g=h.exec(u))!==null)m.push({key:g[1],error:`${g[2]}: ${g[3]}`});return{deleted:d,errors:m}}async list(e,a={}){let r=await this.getCredentials(),n=new URL(this.buildUrl(e));if(n.searchParams.set("list-type","2"),a.prefix)n.searchParams.set("prefix",a.prefix);if(a.delimiter)n.searchParams.set("delimiter",a.delimiter);if(a.maxKeys)n.searchParams.set("max-keys",String(a.maxKeys));if(a.continuationToken)n.searchParams.set("continuation-token",a.continuationToken);if(a.startAfter)n.searchParams.set("start-after",a.startAfter);let i=ae({method:"GET",url:n.toString(),...r,service:"s3",region:this.region}),o=await fetch(i.url,{method:i.method,headers:i.headers});if(!o.ok){let u=await o.text();throw new Ie(`Failed to list objects: ${u}`,o.status,e)}let c=await o.text();return pi(c)}async*listAll(e,a={}){let r;do{let n=await this.list(e,{...a,continuationToken:r});for(let i of n.contents)yield i;r=n.nextContinuationToken}while(r)}async head(e,a){let r=await this.getCredentials(),n=this.buildUrl(e,a),i=ae({method:"HEAD",url:n,...r,service:"s3",region:this.region}),o=await fetch(i.url,{method:i.method,headers:i.headers});if(o.status===404)return null;if(!o.ok){let u=await o.text();throw new Ie(`Failed to head object: ${u}`,o.status,e,a)}let c={};return o.headers.forEach((u,d)=>{if(d.toLowerCase().startsWith("x-amz-meta-"))c[d.slice(11)]=u}),{contentLength:Number(o.headers.get("Content-Length")||0),contentType:o.headers.get("Content-Type")||"application/octet-stream",etag:(o.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(o.headers.get("Last-Modified")||0),metadata:c,storageClass:o.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:o.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,a){return await this.head(e,a)!==null}async copy(e,a,r,n,i={}){let o=await this.getCredentials(),c=this.buildUrl(r,n),u={"x-amz-copy-source":`/${e}/${encodeURIComponent(a)}`};if(i.metadataDirective)u["x-amz-metadata-directive"]=i.metadataDirective;if(i.contentType)u["Content-Type"]=i.contentType;if(i.storageClass)u["x-amz-storage-class"]=i.storageClass;if(i.acl)u["x-amz-acl"]=i.acl;if(i.metadata)for(let[g,h]of Object.entries(i.metadata))u[`x-amz-meta-${g.toLowerCase()}`]=h;let d=ae({method:"PUT",url:c,headers:u,...o,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers});if(!m.ok){let g=await m.text();throw new Ie(`Failed to copy object: ${g}`,m.status,r,n)}let p=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:p?p[1]:""}}async getPresignedUrl(e,a,r={}){let n=await this.getCredentials(),i=this.buildUrl(e,a);return Nd({url:i,method:r.method||"GET",expiresIn:r.expiresIn||3600,...n,service:"s3",region:this.region})}async uploadMultipart(e,a,r,n={}){let i=await this.getCredentials(),o=Math.max(n.partSize||Nt,di),c,u;if(r instanceof ReadableStream)c=r;else if(r instanceof Blob)c=r.stream(),u=r.size;else{let p=new Blob([r]);c=p.stream(),u=p.size}let{uploadId:d,baseUrl:m}=await this.initiateMultipartUpload(e,a,n);try{let p=await this.uploadParts(e,a,m,d,c,o,i,u,n.concurrency||4,n.onProgress);return await this.completeMultipartUpload(e,a,m,d,p)}catch(p){throw await this.abortMultipartUpload(e,a,d,m).catch(()=>{}),p}}async initiateMultipartUpload(e,a,r){let n=await this.getCredentials(),i=this.buildUrl(e,a),o=`${i}?uploads`,c={"Content-Type":r.contentType||_a(a)};if(r.storageClass)c["x-amz-storage-class"]=r.storageClass;if(r.serverSideEncryption)c["x-amz-server-side-encryption"]=r.serverSideEncryption;if(r.acl)c["x-amz-acl"]=r.acl;if(r.metadata)for(let[g,h]of Object.entries(r.metadata))c[`x-amz-meta-${g.toLowerCase()}`]=h;let u=ae({method:"POST",url:o,headers:c,...n,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok){let g=await d.text();throw new Ie(`Failed to initiate multipart upload: ${g}`,d.status,e,a)}let m=(await d.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!m)throw new Ie("Failed to parse upload ID from response",0,e,a);let p=i;if(d.url)try{let g=new URL(d.url);g.search="",p=g.toString()}catch{}return{uploadId:m[1],baseUrl:p}}async uploadParts(e,a,r,n,i,o,c,u,d,m){let p=[],g=i.getReader(),h=1,y=new Uint8Array(0),f=0,b=u?Math.ceil(u/o):void 0,v=new Map,T=async(C,N)=>{let R=`${r}?partNumber=${N}&uploadId=${encodeURIComponent(n)}`,k={"Content-Length":String(C.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},x=ae({method:"PUT",url:R,headers:k,...c,service:"s3",region:this.region}),M=await fetch(x.url,{method:x.method,headers:x.headers,body:C,redirect:"error"});if(!M.ok){let _=await M.text();throw new Ie(`Failed to upload part ${N}: ${_}`,M.status,e,a)}let B=(M.headers.get("ETag")||"").replace(/"/g,"");if(!B)throw new Ie(`Missing ETag for part ${N}`,M.status,e,a);return{partNumber:N,etag:B}},I=async()=>{let C=await Promise.race(v.values());v.delete(C.partNumber),p.push(C)};while(!0){let{done:C,value:N}=await g.read();if(N){let R=new Uint8Array(y.length+N.length);R.set(y),R.set(N,y.length),y=R}while(y.length>=o||C&&y.length>0){let R=y.slice(0,o);y=y.slice(o);let k=h++;if(v.size>=d)await I();if(v.set(k,T(R,k)),f+=R.byteLength,m)m({loaded:f,total:u||f,part:k,totalParts:b||k})}if(C)break}while(v.size>0)await I();return p.sort((C,N)=>C.partNumber-N.partNumber),p}async completeMultipartUpload(e,a,r,n,i){let o=await this.getCredentials(),c=`${r}?uploadId=${encodeURIComponent(n)}`,u=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${i.map((g)=>`<Part><PartNumber>${g.partNumber}</PartNumber><ETag>"${g.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,d=ae({method:"POST",url:c,headers:{"Content-Type":"application/xml"},body:u,...o,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers,body:u});if(!m.ok){let g=await m.text();throw new Ie(`Failed to complete multipart upload: ${g}`,m.status,e,a)}let p=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:p?p[1]:""}}async abortMultipartUpload(e,a,r,n){let i=await this.getCredentials(),o=`${n??this.buildUrl(e,a)}?uploadId=${encodeURIComponent(r)}`,c=ae({method:"DELETE",url:o,...i,service:"s3",region:this.region});await fetch(c.url,{method:c.method,headers:c.headers})}async emptyAndDeleteBucket(e){let a=[];for await(let o of this.listAll(e,{}))if(a.push(o.key),a.length>=1000)await this.deleteMany(e,a),a=[];if(a.length>0)await this.deleteMany(e,a);let r=await this.getCredentials(),n=this.buildUrl(e),i=ae({method:"DELETE",url:n,...r,service:"s3",region:this.region});await fetch(i.url,{method:i.method,headers:i.headers})}}class Ie extends Error{statusCode;bucket;key;constructor(e,a,r,n){super(e);this.statusCode=a,this.bucket=r,this.key=n,this.name="S3Error"}}function pi(e){let a=[],r=[],n=/<Contents>([\s\S]*?)<\/Contents>/g,i;while((i=n.exec(e))!==null){let c=i[1];a.push({key:z(c,"Key")||"",lastModified:new Date(z(c,"LastModified")||0),etag:(z(c,"ETag")||"").replace(/"/g,""),size:Number(z(c,"Size")||0),storageClass:z(c,"StorageClass")||"STANDARD"})}let o=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((i=o.exec(e))!==null)r.push(i[1]);return{contents:a,commonPrefixes:r,isTruncated:z(e,"IsTruncated")==="true",continuationToken:z(e,"ContinuationToken")||void 0,nextContinuationToken:z(e,"NextContinuationToken")||void 0,keyCount:Number(z(e,"KeyCount")||0),maxKeys:Number(z(e,"MaxKeys")||1000),prefix:z(e,"Prefix")||void 0,delimiter:z(e,"Delimiter")||void 0}}function z(e,a){let r=new RegExp(`<${a}>([^<]*)</${a}>`),n=e.match(r);return n?n[1]:null}function gi(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function _a(e){let a=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"}[a||""]||"application/octet-stream"}function fi(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function gm(e){return new kc(e)}await Ye();class Qd{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await pa(this.profile)}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async createInvalidation(e){let a=await this.ensureCredentials(),r=e.callerReference||`invalidation-${Date.now()}`,n=`<?xml version="1.0" encoding="UTF-8"?>
|
|
2497
2497
|
<InvalidationBatch>
|
|
2498
2498
|
<Paths>
|
|
2499
2499
|
<Quantity>${e.paths.length}</Quantity>
|
|
@@ -2517,7 +2517,7 @@ Stack trace:`),console.error(a.stack)}}static success(e){console.log(`✔ ${e}`)
|
|
|
2517
2517
|
`,r=e.reduce((n,i)=>{if(!n[i.service])n[i.service]=[];return n[i.service].push(i),n},{});for(let[n,i]of Object.entries(r)){a+=`${n}:
|
|
2518
2518
|
`;for(let o of i){let c=o.warning?"⚠":"✓";a+=` ${c} ${o.quotaName}: ${o.currentValue}/${o.limit} (${o.percentage.toFixed(1)}%)
|
|
2519
2519
|
`}a+=`
|
|
2520
|
-
`}return a}function Em(e){let a=[];for(let r of e)if(r.percentage>=100)a.push(`Request quota increase for ${r.service} - ${r.quotaName} (currently ${r.limit})`);else if(r.warning)a.push(`Consider requesting quota increase for ${r.service} - ${r.quotaName} (${r.percentage.toFixed(1)}% used)`);return a}class $c{cacheDir;ttl;constructor(e,a={}){this.cacheDir=e,this.ttl=a.ttl||86400000}ensureCacheDir(){if(!st(this.cacheDir))Pi(this.cacheDir,{recursive:!0})}getCachePath(e){let a=or("sha256").update(e).digest("hex");return Dt(this.cacheDir,`${a}.json`)}get(e){let a=this.getCachePath(e);if(!st(a))return;try{let r=Ga(a,"utf-8"),n=JSON.parse(r);if(Date.now()-n.timestamp>this.ttl){Ke(a);return}return n.value}catch{Ke(a);return}}set(e,a,r){this.ensureCacheDir();let n=this.getCachePath(e),i={value:a,timestamp:Date.now(),hash:r};Ri(n,JSON.stringify(i),"utf-8")}has(e){return this.get(e)!==void 0}clear(){if(!st(this.cacheDir))return;let e=Wa(this.cacheDir);for(let a of e)Ke(Dt(this.cacheDir,a))}prune(){if(!st(this.cacheDir))return;let e=Wa(this.cacheDir),a=Date.now();for(let r of e){let n=Dt(this.cacheDir,r);try{let i=Ga(n,"utf-8"),o=JSON.parse(i);if(a-o.timestamp>this.ttl)Ke(n)}catch{Ke(n)}}}}class Oc{cache;constructor(e=et("cache","templates")){this.cache=new $c(e,{ttl:86400000})}getTemplate(e){return this.cache.get(`template:${e}`)}setTemplate(e,a){let r=this.hashTemplate(a);this.cache.set(`template:${e}`,a,r)}hasChanged(e,a){let r=this.cache.get(`template:${e}`);if(!r)return!0;let n=this.hashTemplate(r),i=this.hashTemplate(a);return n!==i}hashTemplate(e){return or("sha256").update(e).digest("hex")}clear(){this.cache.clear()}prune(){this.cache.prune()}}var kt=null;function
|
|
2520
|
+
`}return a}function Em(e){let a=[];for(let r of e)if(r.percentage>=100)a.push(`Request quota increase for ${r.service} - ${r.quotaName} (currently ${r.limit})`);else if(r.warning)a.push(`Consider requesting quota increase for ${r.service} - ${r.quotaName} (${r.percentage.toFixed(1)}% used)`);return a}class $c{cacheDir;ttl;constructor(e,a={}){this.cacheDir=e,this.ttl=a.ttl||86400000}ensureCacheDir(){if(!st(this.cacheDir))Pi(this.cacheDir,{recursive:!0})}getCachePath(e){let a=or("sha256").update(e).digest("hex");return Dt(this.cacheDir,`${a}.json`)}get(e){let a=this.getCachePath(e);if(!st(a))return;try{let r=Ga(a,"utf-8"),n=JSON.parse(r);if(Date.now()-n.timestamp>this.ttl){Ke(a);return}return n.value}catch{Ke(a);return}}set(e,a,r){this.ensureCacheDir();let n=this.getCachePath(e),i={value:a,timestamp:Date.now(),hash:r};Ri(n,JSON.stringify(i),"utf-8")}has(e){return this.get(e)!==void 0}clear(){if(!st(this.cacheDir))return;let e=Wa(this.cacheDir);for(let a of e)Ke(Dt(this.cacheDir,a))}prune(){if(!st(this.cacheDir))return;let e=Wa(this.cacheDir),a=Date.now();for(let r of e){let n=Dt(this.cacheDir,r);try{let i=Ga(n,"utf-8"),o=JSON.parse(i);if(a-o.timestamp>this.ttl)Ke(n)}catch{Ke(n)}}}}class Oc{cache;constructor(e=et("cache","templates")){this.cache=new $c(e,{ttl:86400000})}getTemplate(e){return this.cache.get(`template:${e}`)}setTemplate(e,a){let r=this.hashTemplate(a);this.cache.set(`template:${e}`,a,r)}hasChanged(e,a){let r=this.cache.get(`template:${e}`);if(!r)return!0;let n=this.hashTemplate(r),i=this.hashTemplate(a);return n!==i}hashTemplate(e){return or("sha256").update(e).digest("hex")}clear(){this.cache.clear()}prune(){this.cache.prune()}}var kt=null;function Cm(){if(!kt)kt=new Oc;return kt}async function Lc(e,a={}){let r=a.algorithm||"sha256",n=a.chunkSize||65536;return new Promise((i,o)=>{let c=Qt(r),u=Ni(e,{highWaterMark:n});u.on("data",(d)=>c.update(d)),u.on("end",()=>i(c.digest("hex"))),u.on("error",o)})}function Mc(e,a="sha256"){return Qt(a).update(e).digest("hex")}function wm(e,a="sha256"){return Qt(a).update(e).digest("hex")}async function Am(e,a={}){let r=a.ignorePatterns||["node_modules",".git","dist","build",Ao()],n=[];async function i(o){let c=Di(o,{withFileTypes:!0});for(let u of c){let d=ki(o,u.name),m=$i(e,d);if(r.some((p)=>m.includes(p)))continue;if(u.isDirectory())await i(d);else if(u.isFile()){let p=gt(d),g=await Lc(d,a);n.push({path:m,hash:g,size:p.size,mtime:p.mtimeMs})}}}return await i(e),n}function Im(e){let a=[...e].sort((r,n)=>r.path.localeCompare(n.path)).map((r)=>`${r.path}:${r.hash}`).join(`
|
|
2521
2521
|
`);return Mc(a)}function Rm(e){let a=gt(e);return Mc(`${e}:${a.size}:${a.mtimeMs}`)}function Pm(e,a){let r=new Map(e.map((u)=>[u.path,u])),n=new Map(a.map((u)=>[u.path,u])),i=[],o=[],c=[];for(let[u,d]of n){let m=r.get(u);if(!m)i.push(d);else if(m.hash!==d.hash)o.push(d)}for(let[u,d]of r)if(!n.has(u))c.push(d);return{added:i,modified:o,deleted:c}}class nu{cache;constructor(){this.cache=new Map}get(e){let a=gt(e),r=this.cache.get(e);if(r&&r.mtime===a.mtimeMs&&r.size===a.size)return r.hash;return}set(e,a){let r=gt(e);this.cache.set(e,{hash:a,mtime:r.mtimeMs,size:r.size})}async getOrCompute(e,a={}){let r=this.get(e);if(r)return r;let n=await Lc(e,a);return this.set(e,n),n}clear(){this.cache.clear()}}async function ma(e,a={}){let r=a.concurrency||5,n=a.stopOnError??!0,i=[],o=[],c=Date.now(),u=[...e],d=[];async function m(h,y){try{let f=await h();i[y]=f}catch(f){let b=f instanceof Error?f:Error(String(f));if(o.push(b),n)throw u.length=0,b}}let p=0;while(u.length>0||d.length>0){while(d.length<r&&u.length>0){let h=u.shift(),y=p++,f=m(h,y);d.push(f)}if(d.length>0){await Promise.race(d);for(let h=d.length-1;h>=0;h--)if(await Promise.race([d[h].then(()=>!0),Promise.resolve(!1)]))d.splice(h,1)}if(n&&o.length>0)break}let g=Date.now()-c;return{results:i.filter((h)=>h!==void 0),errors:o,duration:g}}async function Nm(e,a,r={}){let n=e.map((i)=>()=>a(i));return ma(n,r)}async function Dm(e,a,r=5){let n=e.map((o,c)=>()=>a(o,c)),i=await ma(n,{concurrency:r,stopOnError:!1});if(i.errors.length>0)throw AggregateError(i.errors,"Parallel map failed");return i.results}async function km(e,a={}){let r=a.retries||3,n=a.retryDelay||1000,i=e.map((o)=>async()=>{let c;for(let u=0;u<=r;u++)try{return await o()}catch(d){if(c=d instanceof Error?d:Error(String(d)),u<r)await cr(n*(u+1))}throw c});return ma(i,a)}async function _m(e){let a=[];for(let r of e){let n=await r();a.push(n)}return a}function cr(e){return new Promise((a)=>setTimeout(a,e))}async function xm(e,a,r="Operation timed out"){return Promise.race([e(),new Promise((n,i)=>setTimeout(()=>i(Error(r)),a))])}class iu{maxConcurrent;minInterval;queue=[];running=0;lastExecution=0;constructor(e=5,a=100){this.maxConcurrent=e,this.minInterval=a}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 cr(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 ou(e,a){let r=[];for(let n=0;n<e.length;n+=a)r.push(e.slice(n,n+a));return r}async function $m(e,a,r){let n=ou(e,a),i=[];for(let o of n){let c=await r(o);i.push(...c)}return i}function Om(e,a){let r=[],n=[],i=[],o=[],c=e.Resources||{},u=a.Resources||{},d=new Set(Object.keys(c)),m=new Set(Object.keys(u));for(let h of m)if(!d.has(h))r.push(h);for(let h of d)if(!m.has(h))i.push(h);for(let h of m)if(d.has(h)){let y=c[h],f=u[h];if(JSON.stringify(y)!==JSON.stringify(f))n.push(h);else o.push(h)}let p=JSON.stringify(e.Parameters||{})!==JSON.stringify(a.Parameters||{}),g=JSON.stringify(e.Outputs||{})!==JSON.stringify(a.Outputs||{});return{added:r,modified:n,deleted:i,unchanged:o,parametersChanged:p,outputsChanged:g,hasChanges:r.length>0||n.length>0||i.length>0||p||g}}function Lm(e){let a=[];if(!e.hasChanges)return"No changes detected";if(e.added.length>0){a.push(`Added resources (${e.added.length}):`);for(let r of e.added)a.push(` + ${r}`)}if(e.modified.length>0){a.push(`Modified resources (${e.modified.length}):`);for(let r of e.modified)a.push(` ~ ${r}`)}if(e.deleted.length>0){a.push(`Deleted resources (${e.deleted.length}):`);for(let r of e.deleted)a.push(` - ${r}`)}if(e.parametersChanged)a.push("Parameters changed");if(e.outputsChanged)a.push("Outputs changed");return a.join(`
|
|
2522
2522
|
`)}function Mm(e,a,r){if(e.deleted.length>0)return!0;for(let n of e.modified){let i=a.Resources[n],o=r.Resources[n];if(i.Type!==o.Type)return!0;let c=Li(o.Type);for(let u of c){let d=i.Properties?.[u],m=o.Properties?.[u];if(JSON.stringify(d)!==JSON.stringify(m))return!0}}return!1}function Li(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 Um(e){let a=[],r=[],n=[];a.push(...e.added);for(let i of e.modified)r.push(i);return n.push(...e.deleted),{safe:a,caution:r,dangerous:n}}function Bm(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 Fm(e){let a=e.added.length+e.modified.length+e.deleted.length+e.unchanged.length,r=e.added.length+e.modified.length+e.deleted.length,n=a>0?r/a*100:0;return{total:a,added:e.added.length,modified:e.modified.length,deleted:e.deleted.length,unchanged:e.unchanged.length,changePercentage:n}}var jm={$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 Vm(e){let a=[];if(!e.project)a.push("Missing required field: project");else{if(!e.project.name)a.push("Missing required field: project.name");if(!e.project.slug)a.push("Missing required field: project.slug")}if(e.project?.slug&&!/^[a-z0-9-]+$/.test(e.project.slug))a.push("Invalid project.slug: must contain only lowercase letters, numbers, and hyphens");let r=["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&&!r.includes(e.project.region))a.push(`Invalid region: ${e.project.region}. Must be one of: ${r.join(", ")}`);if(e.mode&&!["server","serverless"].includes(e.mode))a.push("Invalid mode: must be one of server or serverless");return{valid:a.length===0,errors:a}}var Uc={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 ga(){return Uc}function zm(){return Uc.enabled}function Hm(e){let a=ga();if(!a.enabled)return"";switch(e.toLowerCase()){case"dynamodb":return a.dynamodbEndpoint;case"s3":return a.s3Endpoint;case"localstack":case"cloudformation":case"lambda":case"apigateway":case"sns":case"sqs":case"cloudwatch":case"iam":case"sts":return a.localstackEndpoint;default:return a.localstackEndpoint}}function qm(){let e=ga();return{accessKeyId:e.awsAccessKeyId,secretAccessKey:e.awsSecretAccessKey,region:e.awsRegion}}function Wm(){let e=ga();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 Bc{stacks=new Map;stackEvents=new Map;async createStack(e){let a=`arn:aws:cloudformation:${e.region||"us-east-1"}:123456789012:stack/${e.StackName}/${Date.now()}`;return this.stacks.set(e.StackName,{StackId:a,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 r=this.stacks.get(e.StackName);if(r)r.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:a}}async updateStack(e){let a=this.stacks.get(e.StackName);if(!a)throw Error(`Stack ${e.StackName} does not exist`);return a.StackStatus="UPDATE_IN_PROGRESS",a.TemplateBody=e.TemplateBody||a.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(()=>{a.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:a.StackId}}async deleteStack(e){let a=this.stacks.get(e.StackName);if(!a)throw Error(`Stack ${e.StackName} does not exist`);a.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 a=this.stacks.get(e.StackName);if(!a)throw Error(`Stack ${e.StackName} does not exist`);return{Stacks:[a]}}return{Stacks:Array.from(this.stacks.values())}}async describeStackEvents(e){return{StackEvents:this.stackEvents.get(e.StackName)||[]}}addEvent(e,a){if(!this.stackEvents.has(e))this.stackEvents.set(e,[]);this.stackEvents.get(e).unshift(a)}reset(){this.stacks.clear(),this.stackEvents.clear()}}class Fc{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 a=this.buckets.get(e.Bucket);if(!a)a=new Map,this.buckets.set(e.Bucket,a);return a.set(e.Key,Buffer.from(e.Body||"")),{ETag:`"${Date.now()}"`}}async getObject(e){let a=this.buckets.get(e.Bucket);if(!a)throw Error(`Bucket ${e.Bucket} does not exist`);let r=a.get(e.Key);if(!r)throw Error(`Object ${e.Key} does not exist`);return{Body:r,ContentLength:r.length}}async deleteObject(e){let a=this.buckets.get(e.Bucket);if(a)a.delete(e.Key)}async listObjects(e){let a=this.buckets.get(e.Bucket);if(!a)throw Error(`Bucket ${e.Bucket} does not exist`);return{Contents:Array.from(a.keys()).map((r)=>({Key:r,Size:a.get(r).length,LastModified:new Date().toISOString()}))}}reset(){this.buckets.clear()}}class jc{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 a=this.data.get(e.TableName);if(!a)a=new Map,this.data.set(e.TableName,a);let r=JSON.stringify(e.Item);a.set(r,e.Item)}async getItem(e){let a=this.data.get(e.TableName);if(!a)return{};let r=JSON.stringify(e.Key),n=a.get(r);return n?{Item:n}:{}}async deleteItem(e){let a=this.data.get(e.TableName);if(a){let r=JSON.stringify(e.Key);a.delete(r)}}async scan(e){let a=this.data.get(e.TableName);if(!a)return{Items:[]};return{Items:Array.from(a.values())}}reset(){this.tables.clear(),this.data.clear()}}function Gm(e){return{cloudformation:new Bc,s3:new Fc,dynamodb:new jc}}class Vc{environments=new Map;async createPreviewEnvironment(e){let{branch:a,pr:r,commitSha:n,ttl:i=24,baseConfig:o,region:c="us-east-1"}=e,u=this.generatePreviewId(a,r,n),d=this.generatePreviewName(a,r),m=`preview-${d}`,p=new Date,g=new Date(p.getTime()+i*60*60*1000),h={id:u,name:d,branch:a,pr:r,commitSha:n,createdAt:p,expiresAt:g,status:"creating",stackName:m,region:c,resources:[]};this.environments.set(u,h);try{let y=this.createPreviewConfig(o,d);return h.status="active",h.url=`https://${d}.preview.example.com`,h}catch(y){throw h.status="failed",y}}async destroyPreviewEnvironment(e){let a=this.environments.get(e);if(!a)throw Error(`Preview environment ${e} not found`);a.status="destroying";try{a.status="destroyed",this.environments.delete(e)}catch(r){throw Error(`Failed to destroy preview environment: ${r}`)}}getPreviewEnvironment(e){return this.environments.get(e)}getPreviewEnvironmentByBranch(e){return Array.from(this.environments.values()).find((a)=>a.branch===e)}getPreviewEnvironmentByPR(e){return Array.from(this.environments.values()).find((a)=>a.pr===e)}listPreviewEnvironments(){return Array.from(this.environments.values())}listActivePreviewEnvironments(){return this.listPreviewEnvironments().filter((e)=>e.status==="active")}async cleanupExpiredEnvironments(e={}){let{maxAge:a,keepCount:r,dryRun:n=!1}=e,i=[],o=[],c=new Date,u=this.listPreviewEnvironments().sort((d,m)=>m.createdAt.getTime()-d.createdAt.getTime());for(let d=0;d<u.length;d++){let m=u[d];if(m.status!=="active")continue;let p=!1;if(m.expiresAt<c)p=!0;if(a){if((c.getTime()-m.createdAt.getTime())/3600000>a)p=!0}if(r&&d>=r)p=!0;if(p)if(n)i.push(m.id);else try{await this.destroyPreviewEnvironment(m.id),i.push(m.id)}catch(g){o.push(m.id)}}return{destroyed:i,failed:o}}async updatePreviewEnvironment(e,a){let r=this.environments.get(e);if(!r)throw Error(`Preview environment ${e} not found`);r.commitSha=a,r.status="creating";try{return r.status="active",r}catch(n){throw r.status="failed",n}}async getPreviewEnvironmentsCost(){let e={},a=0;for(let r of this.environments.values())e[r.id]=0,a+=0;return{total:a,byEnvironment:e}}generatePreviewId(e,a,r){let n=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase(),i=r?.substring(0,7)||Date.now().toString();return a?`pr-${a}-${i}`:`${n}-${i}`}generatePreviewName(e,a){let r=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase();return a?`pr-${a}`:r}createPreviewConfig(e,a){return{...e,project:{...e.project,name:`${e.project.name} Preview (${a})`,slug:`${e.project.slug}-preview-${a}`}}}}var Km=new Vc;function Jm(e={}){let{workflowName:a="Preview Environment",trigger:r="pull_request",branches:n=["main","develop"],awsRegion:i="us-east-1",awsRole:o,configFile:c="cloud.config.ts",ttl:u=24}=e;return`name: ${a}
|
|
2523
2523
|
|
|
@@ -2771,7 +2771,7 @@ ${a.map((r)=>` • ${r}`).join(`
|
|
|
2771
2771
|
`))}catch(e){console.error(`Failed to save history: ${e}`)}}searchHistory(e){return this.history.commands.filter((a)=>a.includes(e))}clearHistory(){this.history.commands=[],this.historyIndex=0}}class uu{variables=new Map;workingDirectory=process.cwd();set(e,a){this.variables.set(e,a)}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 pu{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 mu{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 a=e.toLowerCase();return this.entries.filter((r)=>r.command.toLowerCase().includes(a))}searchByDate(e,a){return this.entries.filter((r)=>r.timestamp>=e&&r.timestamp<=a)}getSuccessful(){return this.entries.filter((e)=>e.success)}getFailed(){return this.entries.filter((e)=>!e.success)}getMostUsed(e=10){let a=new Map;for(let r of this.entries){let n=r.command.split(" ")[0];a.set(n,(a.get(n)||0)+1)}return Array.from(a.entries()).map(([r,n])=>({command:r,count:n})).sort((r,n)=>n.count-r.count).slice(0,e)}getStats(){let e=this.entries.length,a=this.entries.filter((u)=>u.success).length,r=this.entries.filter((u)=>!u.success).length,n=this.entries.filter((u)=>u.duration!==void 0),i=n.length>0?n.reduce((u,d)=>u+(d.duration||0),0)/n.length:0,o=this.getMostUsed(1),c=o.length>0?o[0].command:"N/A";return{total:e,successful:a,failed:r,averageDuration:i,mostUsed:c}}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"),a=JSON.stringify(this.entries,null,2);await e.writeFile(this.persistFile,a,"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"),a=await e.readFile(this.persistFile,"utf-8"),r=JSON.parse(a);this.entries=r.map((n)=>({...n,timestamp:new Date(n.timestamp)}))}catch{this.entries=[]}}exportJSON(){return JSON.stringify(this.entries,null,2)}exportCSV(){return["Timestamp,Command,Success,Duration",...this.entries.map((e)=>[e.timestamp.toISOString(),`"${e.command.replace(/"/g,'""')}"`,e.success,e.duration||""].join(","))].join(`
|
|
2772
2772
|
`)}importJSON(e){let a=JSON.parse(e).map((r)=>({...r,timestamp:new Date(r.timestamp)}));if(this.entries.push(...a),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}groupByDate(){let e=new Map;for(let a of this.entries){let r=a.timestamp.toISOString().split("T")[0];if(!e.has(r))e.set(r,[]);e.get(r).push(a)}return e}groupByCommand(){let e=new Map;for(let a of this.entries){let r=a.command.split(" ")[0];if(!e.has(r))e.set(r,[]);e.get(r).push(a)}return e}replay(e){return this.getByIndex(e)?.command}getSuggestions(e,a=5){let r=e.toLowerCase(),n=this.entries.filter((i)=>i.command.toLowerCase().startsWith(r)).map((i)=>i.command);return[...new Set(n)].slice(0,a)}analyzePatterns(){let e=new Map,a=new Map;for(let n of this.entries){let i=n.timestamp.getHours(),o=n.timestamp.getDay();e.set(i,(e.get(i)||0)+1),a.set(o,(a.get(o)||0)+1)}let r=this.entries.length>0?this.getSuccessful().length/this.entries.length:0;return{timeOfDay:e,dayOfWeek:a,successRate:r}}}function fg(e,a={}){let{maxWidth:r=100}=a;if(e.length===0)return"No command history";let n=[];for(let i=0;i<e.length;i++){let o=e[i],c=(i+1).toString().padStart(4),u=o.timestamp.toLocaleString(),d=o.success?"✓":"✗",m=o.command;if(m.length>r-30)m=m.substring(0,r-33)+"...";let p=`${c} ${u} ${d} ${m}`;if(o.duration)p+=` (${o.duration}ms)`;n.push(p)}return n.join(`
|
|
2773
2773
|
`)}function hg(e){let a=[];return a.push("Command History Statistics"),a.push("─".repeat(30)),a.push(`Total commands: ${e.total}`),a.push(`Successful: ${e.successful}`),a.push(`Failed: ${e.failed}`),a.push(`Success rate: ${(e.successful/e.total*100).toFixed(1)}%`),a.push(`Average duration: ${e.averageDuration.toFixed(0)}ms`),a.push(`Most used: ${e.mostUsed}`),a.join(`
|
|
2774
|
-
`)}class qc{deployments=new Map;async deploy(e,a){let r=this.generateDeploymentId(),n={id:r,regions:a.regions.map((i)=>({region:i.code,stackName:this.getStackName(e,i.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(r,n);try{let i=a.regions.find((c)=>c.isPrimary)||a.regions[0];await this.deployToRegion(e,i,n);let o=a.regions.filter((c)=>c.code!==i.code);if(await Promise.all(o.map((c)=>this.deployToRegion(e,c,n))),a.globalResources)await this.deployGlobalResources(n,a);if(a.replication)await this.setupReplication(n,a);if(a.failover?.enabled)await this.setupFailover(n,a);return n.status="deployed",n.endTime=new Date,n}catch(i){throw n.status="failed",n.endTime=new Date,i}}async deployToRegion(e,a,r){let n=r.regions.find((i)=>i.region===a.code);if(!n)throw Error(`Region deployment not found: ${a.code}`);n.status="deploying",n.startTime=new Date;try{let i=this.createRegionConfig(e,a);await this.deployStack(n.stackName,i,a.code),n.status="deployed",n.endTime=new Date,n.outputs={stackId:`arn:aws:cloudformation:${a.code}:123456789012:stack/${n.stackName}/guid`,endpoint:`https://${n.stackName}.${a.code}.example.com`}}catch(i){throw n.status="failed",n.endTime=new Date,n.error=i instanceof Error?i.message:String(i),i}}async deployGlobalResources(e,a){let r={};if(a.globalResources?.route53)r.route53=await this.deployRoute53(e,a);if(a.globalResources?.cloudfront)r.cloudfront=await this.deployCloudFront(e,a);if(a.globalResources?.waf)r.waf=await this.deployWAF(e);e.globalResources=r}async deployRoute53(e,a){let r=[],n=[];for(let i of e.regions){if(i.status!=="deployed")continue;let o={id:`health-${i.region}`,endpoint:i.outputs?.endpoint,path:a.failover?.healthCheckPath||"/health",region:i.region};r.push(o);let c={name:"example.com",type:"A",region:i.region,setIdentifier:i.region,healthCheckId:o.id,resourceRecords:[i.outputs?.endpoint]};n.push(c)}return{healthChecks:r,recordSets:n,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(e,a){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:e.regions.filter((r)=>r.status==="deployed").map((r,n)=>{let i=a.regions[n];return{id:`origin-${r.region}`,domainName:r.outputs?.endpoint,weight:i?.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,a){if(a.replication?.s3)await this.setupS3Replication(e);if(a.replication?.dynamodb)await this.setupDynamoDBReplication(e);if(a.replication?.secrets)await this.setupSecretsReplication(e)}async setupS3Replication(e){let a=e.regions.filter((r)=>r.status==="deployed");for(let r=0;r<a.length-1;r++){let n=a[r],i=a[r+1];console.log(`Setting up S3 replication: ${n.region} -> ${i.region}`)}}async setupDynamoDBReplication(e){let a=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up DynamoDB global table in regions: ${a.join(", ")}`)}async setupSecretsReplication(e){let a=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up Secrets Manager replication in regions: ${a.join(", ")}`)}async setupFailover(e,a){let r=e.regions.find((i,o)=>a.regions[o]?.isPrimary)||e.regions[0],n=e.regions.filter((i)=>i.region!==r.region);console.log(`Setting up failover: primary=${r.region}, secondary=${n.map((i)=>i.region).join(", ")}`)}async destroy(e){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);a.status="rolling-back";try{if(a.globalResources)await this.destroyGlobalResources(a.globalResources);await Promise.all(a.regions.map((r)=>this.destroyRegionStack(r))),this.deployments.delete(e)}catch(r){throw a.status="failed",r}}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(a){throw e.status="failed",e.error=a instanceof Error?a.message:String(a),a}}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getStackName(e,a){return`${e.project.slug}-${a}`}createRegionConfig(e,a){return{...e,infrastructure:{...e.infrastructure}}}async deployStack(e,a,r){console.log(`Deploying stack ${e} to ${r}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var yg=new qc;class Wc{references=[];exports=new Map;addExport(e){let a=`${e.region}:${e.exportName}`;if(!this.exports.has(e.region))this.exports.set(e.region,[]);this.exports.get(e.region).push(e)}getExport(e,a){let r=this.exports.get(e);if(!r)return;return r.find((n)=>n.exportName===a)?.value}createReference(e,a,r,n){let i=`/cross-region/${e}/${r}/${n}`;return this.references.push({sourceRegion:e,targetRegion:a,resourceType:r,resourceId:n,value:i}),i}async resolveReference(e,a){let r=this.references.find((n)=>n.targetRegion===e&&n.value===a);if(!r)throw Error(`Reference not found: ${a}`);return`arn:aws:resource:${r.sourceRegion}:123456789012:${r.resourceType}/${r.resourceId}`}getReferencesForRegion(e){return this.references.filter((a)=>a.sourceRegion===e||a.targetRegion===e)}clear(){this.references=[],this.exports.clear()}}class Gc{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((a)=>a.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 Kc{pairs=[];addPair(e){this.pairs.push(e)}getPairedRegion(e){let a=this.pairs.find((r)=>r.primary===e||r.secondary===e);if(!a)return;return a.primary===e?a.secondary:a.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((e)=>e.replicationConfig)}getFailoverPairs(){return this.pairs.filter((e)=>e.failoverConfig?.automatic)}arePaired(e,a){return this.pairs.some((r)=>r.primary===e&&r.secondary===a||r.primary===a&&r.secondary===e)}clear(){this.pairs=[]}}class Jc{dependencies=[];addDependency(e){this.dependencies.push(e)}getDependencies(e,a){return this.dependencies.filter((r)=>r.dependentStack===e&&r.dependentRegion===a)}getDependents(e,a){return this.dependencies.filter((r)=>r.dependsOnStack===e&&r.dependsOnRegion===a)}hasDependencies(e,a){return this.getDependencies(e,a).length>0}getDeploymentOrder(e){let a=new Set,r=[],n=(i)=>{let o=`${i.name}:${i.region}`;if(a.has(o))return;a.add(o);let c=this.getDependencies(i.name,i.region);for(let u of c)n({name:u.dependsOnStack,region:u.dependsOnRegion});r.push(i)};for(let i of e)n(i);return r}detectCircularDependencies(){let e=new Set,a=new Set,r=(n,i)=>{let o=`${n}:${i}`;if(a.has(o))return!0;if(e.has(o))return!1;e.add(o),a.add(o);let c=this.getDependencies(n,i);for(let u of c)if(r(u.dependsOnStack,u.dependsOnRegion))return!0;return a.delete(o),!1};for(let n of this.dependencies)if(r(n.dependentStack,n.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var Sg=new Wc,bg=new Gc,vg=new Kc,Tg=new Jc,rt=[{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 Ci(e){return rt.find((a)=>a.code===e)}function Eg(){return rt}function wg(e){let a=e.toLowerCase();return rt.filter((r)=>r.location.toLowerCase().includes(a))}function Cg(e){return rt.filter((a)=>a.compliance.includes(e))}function Ag(e){return rt.filter((a)=>a.pricing.tier===e)}function Ig(e){return rt.some((a)=>a.code===e)}function Rg(e){if(e.continent==="North America")return Ci("us-east-1");if(e.continent==="Europe")return Ci("eu-west-1");if(e.continent==="Asia")return Ci("ap-southeast-1");return Ci("us-east-1")}function Pg(e){let a=[...rt];if(e.compliance)a=a.filter((r)=>e.compliance.every((n)=>r.compliance.includes(n)));if(e.requiredServices)a=a.filter((r)=>e.requiredServices.every((n)=>r.services[n]));if(e.pricingSensitive)a.sort((r,n)=>r.pricing.multiplier-n.pricing.multiplier);return a.slice(0,5)}function Ng(e){let a=Ci(e);if(!a)throw Error(`Invalid region: ${e}`);let r=[];for(let n of rt){if(n.code===e)continue;let i=_i(a,n),o=Wi(a,n);r.push({primary:a,secondary:n,distance:i,sameContinent:o})}return r.sort((n,i)=>{if(n.sameContinent!==i.sameContinent)return n.sameContinent?1:-1;return n.distance-i.distance}),r.slice(0,3)}function _i(e,a){let r={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},n=Je(e.location),i=Je(a.location);return Math.abs((r[n]||0)-(r[i]||0))}function Wi(e,a){return Je(e.location)===Je(a.location)}function Je(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 gu(e){return`${e.name} (${e.code})`}function Dg(e){return e.map((a)=>gu(a)).join(`
|
|
2774
|
+
`)}class qc{deployments=new Map;async deploy(e,a){let r=this.generateDeploymentId(),n={id:r,regions:a.regions.map((i)=>({region:i.code,stackName:this.getStackName(e,i.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(r,n);try{let i=a.regions.find((c)=>c.isPrimary)||a.regions[0];await this.deployToRegion(e,i,n);let o=a.regions.filter((c)=>c.code!==i.code);if(await Promise.all(o.map((c)=>this.deployToRegion(e,c,n))),a.globalResources)await this.deployGlobalResources(n,a);if(a.replication)await this.setupReplication(n,a);if(a.failover?.enabled)await this.setupFailover(n,a);return n.status="deployed",n.endTime=new Date,n}catch(i){throw n.status="failed",n.endTime=new Date,i}}async deployToRegion(e,a,r){let n=r.regions.find((i)=>i.region===a.code);if(!n)throw Error(`Region deployment not found: ${a.code}`);n.status="deploying",n.startTime=new Date;try{let i=this.createRegionConfig(e,a);await this.deployStack(n.stackName,i,a.code),n.status="deployed",n.endTime=new Date,n.outputs={stackId:`arn:aws:cloudformation:${a.code}:123456789012:stack/${n.stackName}/guid`,endpoint:`https://${n.stackName}.${a.code}.example.com`}}catch(i){throw n.status="failed",n.endTime=new Date,n.error=i instanceof Error?i.message:String(i),i}}async deployGlobalResources(e,a){let r={};if(a.globalResources?.route53)r.route53=await this.deployRoute53(e,a);if(a.globalResources?.cloudfront)r.cloudfront=await this.deployCloudFront(e,a);if(a.globalResources?.waf)r.waf=await this.deployWAF(e);e.globalResources=r}async deployRoute53(e,a){let r=[],n=[];for(let i of e.regions){if(i.status!=="deployed")continue;let o={id:`health-${i.region}`,endpoint:i.outputs?.endpoint,path:a.failover?.healthCheckPath||"/health",region:i.region};r.push(o);let c={name:"example.com",type:"A",region:i.region,setIdentifier:i.region,healthCheckId:o.id,resourceRecords:[i.outputs?.endpoint]};n.push(c)}return{healthChecks:r,recordSets:n,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(e,a){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:e.regions.filter((r)=>r.status==="deployed").map((r,n)=>{let i=a.regions[n];return{id:`origin-${r.region}`,domainName:r.outputs?.endpoint,weight:i?.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,a){if(a.replication?.s3)await this.setupS3Replication(e);if(a.replication?.dynamodb)await this.setupDynamoDBReplication(e);if(a.replication?.secrets)await this.setupSecretsReplication(e)}async setupS3Replication(e){let a=e.regions.filter((r)=>r.status==="deployed");for(let r=0;r<a.length-1;r++){let n=a[r],i=a[r+1];console.log(`Setting up S3 replication: ${n.region} -> ${i.region}`)}}async setupDynamoDBReplication(e){let a=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up DynamoDB global table in regions: ${a.join(", ")}`)}async setupSecretsReplication(e){let a=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up Secrets Manager replication in regions: ${a.join(", ")}`)}async setupFailover(e,a){let r=e.regions.find((i,o)=>a.regions[o]?.isPrimary)||e.regions[0],n=e.regions.filter((i)=>i.region!==r.region);console.log(`Setting up failover: primary=${r.region}, secondary=${n.map((i)=>i.region).join(", ")}`)}async destroy(e){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);a.status="rolling-back";try{if(a.globalResources)await this.destroyGlobalResources(a.globalResources);await Promise.all(a.regions.map((r)=>this.destroyRegionStack(r))),this.deployments.delete(e)}catch(r){throw a.status="failed",r}}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(a){throw e.status="failed",e.error=a instanceof Error?a.message:String(a),a}}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getStackName(e,a){return`${e.project.slug}-${a}`}createRegionConfig(e,a){return{...e,infrastructure:{...e.infrastructure}}}async deployStack(e,a,r){console.log(`Deploying stack ${e} to ${r}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var yg=new qc;class Wc{references=[];exports=new Map;addExport(e){let a=`${e.region}:${e.exportName}`;if(!this.exports.has(e.region))this.exports.set(e.region,[]);this.exports.get(e.region).push(e)}getExport(e,a){let r=this.exports.get(e);if(!r)return;return r.find((n)=>n.exportName===a)?.value}createReference(e,a,r,n){let i=`/cross-region/${e}/${r}/${n}`;return this.references.push({sourceRegion:e,targetRegion:a,resourceType:r,resourceId:n,value:i}),i}async resolveReference(e,a){let r=this.references.find((n)=>n.targetRegion===e&&n.value===a);if(!r)throw Error(`Reference not found: ${a}`);return`arn:aws:resource:${r.sourceRegion}:123456789012:${r.resourceType}/${r.resourceId}`}getReferencesForRegion(e){return this.references.filter((a)=>a.sourceRegion===e||a.targetRegion===e)}clear(){this.references=[],this.exports.clear()}}class Gc{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((a)=>a.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 Kc{pairs=[];addPair(e){this.pairs.push(e)}getPairedRegion(e){let a=this.pairs.find((r)=>r.primary===e||r.secondary===e);if(!a)return;return a.primary===e?a.secondary:a.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((e)=>e.replicationConfig)}getFailoverPairs(){return this.pairs.filter((e)=>e.failoverConfig?.automatic)}arePaired(e,a){return this.pairs.some((r)=>r.primary===e&&r.secondary===a||r.primary===a&&r.secondary===e)}clear(){this.pairs=[]}}class Jc{dependencies=[];addDependency(e){this.dependencies.push(e)}getDependencies(e,a){return this.dependencies.filter((r)=>r.dependentStack===e&&r.dependentRegion===a)}getDependents(e,a){return this.dependencies.filter((r)=>r.dependsOnStack===e&&r.dependsOnRegion===a)}hasDependencies(e,a){return this.getDependencies(e,a).length>0}getDeploymentOrder(e){let a=new Set,r=[],n=(i)=>{let o=`${i.name}:${i.region}`;if(a.has(o))return;a.add(o);let c=this.getDependencies(i.name,i.region);for(let u of c)n({name:u.dependsOnStack,region:u.dependsOnRegion});r.push(i)};for(let i of e)n(i);return r}detectCircularDependencies(){let e=new Set,a=new Set,r=(n,i)=>{let o=`${n}:${i}`;if(a.has(o))return!0;if(e.has(o))return!1;e.add(o),a.add(o);let c=this.getDependencies(n,i);for(let u of c)if(r(u.dependsOnStack,u.dependsOnRegion))return!0;return a.delete(o),!1};for(let n of this.dependencies)if(r(n.dependentStack,n.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var Sg=new Wc,bg=new Gc,vg=new Kc,Tg=new Jc,rt=[{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 wi(e){return rt.find((a)=>a.code===e)}function Eg(){return rt}function Cg(e){let a=e.toLowerCase();return rt.filter((r)=>r.location.toLowerCase().includes(a))}function wg(e){return rt.filter((a)=>a.compliance.includes(e))}function Ag(e){return rt.filter((a)=>a.pricing.tier===e)}function Ig(e){return rt.some((a)=>a.code===e)}function Rg(e){if(e.continent==="North America")return wi("us-east-1");if(e.continent==="Europe")return wi("eu-west-1");if(e.continent==="Asia")return wi("ap-southeast-1");return wi("us-east-1")}function Pg(e){let a=[...rt];if(e.compliance)a=a.filter((r)=>e.compliance.every((n)=>r.compliance.includes(n)));if(e.requiredServices)a=a.filter((r)=>e.requiredServices.every((n)=>r.services[n]));if(e.pricingSensitive)a.sort((r,n)=>r.pricing.multiplier-n.pricing.multiplier);return a.slice(0,5)}function Ng(e){let a=wi(e);if(!a)throw Error(`Invalid region: ${e}`);let r=[];for(let n of rt){if(n.code===e)continue;let i=_i(a,n),o=Wi(a,n);r.push({primary:a,secondary:n,distance:i,sameContinent:o})}return r.sort((n,i)=>{if(n.sameContinent!==i.sameContinent)return n.sameContinent?1:-1;return n.distance-i.distance}),r.slice(0,3)}function _i(e,a){let r={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},n=Je(e.location),i=Je(a.location);return Math.abs((r[n]||0)-(r[i]||0))}function Wi(e,a){return Je(e.location)===Je(a.location)}function Je(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 gu(e){return`${e.name} (${e.code})`}function Dg(e){return e.map((a)=>gu(a)).join(`
|
|
2775
2775
|
`)}function kg(){let e={total:rt.length,byContinent:{},byPricingTier:{}};for(let a of rt){let r=Je(a.location);e.byContinent[r]=(e.byContinent[r]||0)+1,e.byPricingTier[a.pricing.tier]=(e.byPricingTier[a.pricing.tier]||0)+1}return e}class Xc{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((a)=>a.alias===e)}listAccounts(){return Array.from(this.accounts.values())}getAccountsByRole(e){return Array.from(this.accounts.values()).filter((a)=>a.role===e)}createCrossAccountRole(e,a,r,n,i){let o={roleArn:`arn:aws:iam::${a}:role/${r}`,roleName:r,sourceAccountId:e,targetAccountId:a,permissions:n,externalId:i?.externalId,sessionDuration:i?.sessionDuration||3600};return this.crossAccountRoles.push(o),o}getAssumeRolePolicyDocument(e,a){let r={Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e}:root`},Action:"sts:AssumeRole"}]};if(a)r.Statement[0].Condition={StringEquals:{"sts:ExternalId":a}};return r}generateCrossAccountPolicy(e){return{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e,Resource:"*"}]}}mapEnvironmentToAccount(e,a,r){this.accountMappings.push({environment:e,accountId:a,region:r})}getAccountForEnvironment(e){return this.accountMappings.find((a)=>a.environment===e)}async assumeRole(e,a,r){return console.log(`Assuming role: ${e} with session: ${a}`),{accessKeyId:"AKIAIOSFODNN7EXAMPLE",secretAccessKey:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",sessionToken:"token",expiration:new Date(Date.now()+3600000)}}async getCredentialsForAccount(e){let a=this.accounts.get(e);if(!a)throw Error(`Account not found: ${e}`);if(a.assumeRoleArn){let r=await this.assumeRole(a.assumeRoleArn,`ts-cloud-${Date.now()}`);return{accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken}}throw Error("No credentials available for account")}listCrossAccountRoles(){return[...this.crossAccountRoles]}getCrossAccountRolesForAccount(e){return this.crossAccountRoles.filter((a)=>a.sourceAccountId===e||a.targetAccountId===e)}async validateAccountAccess(e){try{let a=await this.getCredentialsForAccount(e);return console.log(`Validating access to account: ${e}`),!0}catch{return!1}}async getConsolidatedBilling(){let e={};for(let a of this.accounts.values())e[a.id]=Math.random()*1000;return{totalCost:Object.values(e).reduce((a,r)=>a+r,0),byAccount:e}}clear(){this.accounts.clear(),this.crossAccountRoles=[],this.accountMappings=[]}}class Qc{organizationId;organizationalUnits=new Map;getOrganizationId(){return this.organizationId}setOrganizationId(e){this.organizationId=e}createOrganizationalUnit(e,a){let r={id:`ou-${Date.now()}`,name:e,parentId:a,accounts:[]};return this.organizationalUnits.set(r.id,r),r}getOrganizationalUnit(e){return this.organizationalUnits.get(e)}listOrganizationalUnits(){return Array.from(this.organizationalUnits.values())}addAccountToOU(e,a){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);if(!r.accounts.includes(a))r.accounts.push(a)}removeAccountFromOU(e,a){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);r.accounts=r.accounts.filter((n)=>n!==a)}getAccountsInOU(e){let a=this.organizationalUnits.get(e);if(!a)return[];return[...a.accounts]}applyServiceControlPolicy(e,a){return{id:`scp-${Date.now()}`,name:"Custom SCP",targetId:e,policyDocument:a}}clear(){this.organizationId=void 0,this.organizationalUnits.clear()}}var _g=new Xc,xg=new Qc,fu={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"}]}},$g={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"]}}}]}}},Og={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 Lg(e){return fu[e]}function Mg(e,a){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:"*"}]}}],...a&&{ManagedPolicyArns:a},MaxSessionDuration:e.sessionDuration||3600,Tags:[{Key:"ManagedBy",Value:"TS-Cloud"},{Key:"SourceAccount",Value:e.sourceAccountId}]}}}function Ug(e){let a=[],r=[],n=e.accounts.filter((d)=>d.role==="management");if(n.length===0)a.push("No management account defined");if(n.length>1)a.push("Multiple management accounts defined");let i=e.accounts.map((d)=>d.email),o=i.filter((d,m)=>i.indexOf(d)!==m);if(o.length>0)a.push(`Duplicate email addresses: ${o.join(", ")}`);let c=e.accounts.map((d)=>d.alias),u=c.filter((d,m)=>c.indexOf(d)!==m);if(u.length>0)a.push(`Duplicate aliases: ${u.join(", ")}`);if(!e.accounts.some((d)=>d.role==="security"))r.push("No dedicated security account - consider adding one for audit logs");if(e.accounts.length<3)r.push("Less than 3 accounts - consider separating environments");if(!e.accounts.some((d)=>d.role==="production"))r.push("No production account defined");return{valid:a.length===0,errors:a,warnings:r}}function Bg(e){let a=[];if(a.push(`${e.name}`),a.push("─".repeat(e.name.length)),a.push(e.description),a.push(""),e.organizationalUnits){a.push("Organizational Units:");for(let r of e.organizationalUnits){let n=r.parent?" └─ ":" ";a.push(`${n}${r.name}`)}a.push("")}a.push("Accounts:");for(let r of e.accounts)a.push(` ${r.alias.padEnd(20)} ${r.role.padEnd(15)} ${r.email}`),a.push(` ${"".padEnd(20)} ${r.description}`),a.push("");return a.join(`
|
|
2776
2776
|
`)}function Fg(e={}){let{workflowName:a="Deploy",trigger:r="push",branches:n=["main"],environments:i=["production"],awsRegion:o="us-east-1",awsRole:c,bunVersion:u="latest",deployCommand:d="bun run cloud deploy",testCommand:m="bun test",buildCommand:p="bun run build"}=e,g=!!c;return`name: ${a}
|
|
2777
2777
|
|
|
@@ -3778,12 +3778,12 @@ Renewing certificate: ${r.domainName}`),console.log(`Certificate ARN: ${r.arn}`)
|
|
|
3778
3778
|
✓ Certificate renewed successfully`),console.log(` New expiration: ${r.expiresAt.toISOString()}`),console.log(` Next renewal: ${a.nextRenewal.toISOString()}`),{success:!0,message:"Certificate renewed successfully"}}catch(n){return a.renewalStatus="failed",this.createAlert({certificateArn:r.arn,alertType:"renewal_failed",severity:"critical",message:`Certificate renewal failed: ${n}`}),{success:!1,message:n instanceof Error?n.message:String(n)}}}createMonitor(e){let a=`monitor-${Date.now()}-${this.monitorCounter++}`,r={id:a,...e};return this.monitors.set(a,r),r}checkExpiration(){let e=[],a=Date.now();for(let r of this.certificates.values()){if(!r.expiresAt)continue;let n=(r.expiresAt.getTime()-a)/86400000;if(n<0)e.push(this.createAlert({certificateArn:r.arn,alertType:"expired",severity:"critical",message:`Certificate has expired for ${r.domainName}`}));else if(n<30)e.push(this.createAlert({certificateArn:r.arn,alertType:"expiring_soon",severity:n<7?"critical":"warning",message:`Certificate expiring in ${Math.floor(n)} days for ${r.domainName}`}))}return e}createAlert(e){let a=`alert-${Date.now()}-${this.alertCounter++}`,r={id:a,timestamp:new Date,acknowledged:!1,...e};return this.alerts.set(a,r),r}acknowledgeAlert(e){let a=this.alerts.get(e);if(a)a.acknowledged=!0}getCertificate(e){return this.certificates.get(e)}listCertificates(){return Array.from(this.certificates.values())}getExpiringCertificates(e=30){let a=Date.now()+e*24*60*60*1000;return Array.from(this.certificates.values()).filter((r)=>r.expiresAt&&r.expiresAt.getTime()<a)}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((a)=>a.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 Ef=new fl;class hl{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 a=`scan-${Date.now()}-${this.scanCounter++}`,r={id:a,status:"queued",findings:[],...e};return this.scans.set(a,r),r}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 a=this.scans.get(e);if(!a)throw Error(`Scan not found: ${e}`);console.log(`
|
|
3779
3779
|
Executing security scan: ${a.name}`),console.log(`Scan type: ${a.scanType}`),console.log(`Target: ${a.target.type} - ${a.target.identifier}`),a.status="running",a.startedAt=new Date;try{console.log(`
|
|
3780
3780
|
Scanning...`);let r=this.simulateFindings(a);return a.findings=r,a.status="completed",a.completedAt=new Date,a.summary={totalFindings:r.length,criticalCount:r.filter((n)=>n.severity==="CRITICAL").length,highCount:r.filter((n)=>n.severity==="HIGH").length,mediumCount:r.filter((n)=>n.severity==="MEDIUM").length,lowCount:r.filter((n)=>n.severity==="LOW").length,infoCount:r.filter((n)=>n.severity==="INFO").length,executionTime:a.completedAt.getTime()-a.startedAt.getTime()},console.log(`
|
|
3781
|
-
✓ Scan completed`),console.log(` Findings: ${a.summary.totalFindings}`),console.log(` Critical: ${a.summary.criticalCount}`),console.log(` High: ${a.summary.highCount}`),console.log(` Medium: ${a.summary.mediumCount}`),console.log(` Low: ${a.summary.lowCount}`),a}catch(r){throw a.status="failed",a.completedAt=new Date,r}}simulateFindings(e){let a=[],r=new Date;if(e.scanType==="container_image")a.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:r,lastSeen:r})),a.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:r,lastSeen:r}));else if(e.scanType==="secrets_detection")a.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:r,lastSeen:r}));return a}createFinding(e){let a=`finding-${Date.now()}-${this.findingCounter++}`,r={id:a,...e};return this.findings.set(a,r),r}suppressFinding(e,a){let r=this.findings.get(e);if(r){if(r.status="SUPPRESSED",console.log(`Finding suppressed: ${r.title}`),a)console.log(`Reason: ${a}`)}}resolveFinding(e){let a=this.findings.get(e);if(a)a.status="RESOLVED",console.log(`Finding resolved: ${a.title}`)}generateReport(e){let a=`report-${Date.now()}-${this.reportCounter++}`,r={id:a,scanId:e.scanId,reportType:e.reportType,format:e.format,generatedAt:new Date,s3Location:`s3://security-reports/${a}.${e.format}`};return this.reports.set(a,r),r}runComplianceCheck(e){let a=[];if(e.framework.includes("CIS"))a.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})),a.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 a}createComplianceCheck(e){let a=`check-${Date.now()}-${this.checkCounter++}`,r={id:a,...e};return this.complianceChecks.set(a,r),r}assessSecurityPosture(e){let a=`posture-${Date.now()}-${this.postureCounter++}`,r=Array.from(this.complianceChecks.values()),n=r.filter((d)=>d.status==="PASS").length,i=r.length,o=i>0?Math.round(n/i*100):0,c;if(o>=90)c="A";else if(o>=80)c="B";else if(o>=70)c="C";else if(o>=60)c="D";else c="F";let u={id:a,accountId:e.accountId,region:e.region,score:o,grade:c,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(a,u),u}getScan(e){return this.scans.get(e)}listScans(){return Array.from(this.scans.values())}getOpenFindings(e){return Array.from(this.findings.values()).filter((a)=>a.status==="OPEN"&&(!e||a.severity===e))}getComplianceChecksByStatus(e){return Array.from(this.complianceChecks.values()).filter((a)=>a.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: ${a.summary.totalFindings}`),console.log(` Critical: ${a.summary.criticalCount}`),console.log(` High: ${a.summary.highCount}`),console.log(` Medium: ${a.summary.mediumCount}`),console.log(` Low: ${a.summary.lowCount}`),a}catch(r){throw a.status="failed",a.completedAt=new Date,r}}simulateFindings(e){let a=[],r=new Date;if(e.scanType==="container_image")a.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:r,lastSeen:r})),a.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:r,lastSeen:r}));else if(e.scanType==="secrets_detection")a.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:r,lastSeen:r}));return a}createFinding(e){let a=`finding-${Date.now()}-${this.findingCounter++}`,r={id:a,...e};return this.findings.set(a,r),r}suppressFinding(e,a){let r=this.findings.get(e);if(r){if(r.status="SUPPRESSED",console.log(`Finding suppressed: ${r.title}`),a)console.log(`Reason: ${a}`)}}resolveFinding(e){let a=this.findings.get(e);if(a)a.status="RESOLVED",console.log(`Finding resolved: ${a.title}`)}generateReport(e){let a=`report-${Date.now()}-${this.reportCounter++}`,r={id:a,scanId:e.scanId,reportType:e.reportType,format:e.format,generatedAt:new Date,s3Location:`s3://security-reports/${a}.${e.format}`};return this.reports.set(a,r),r}runComplianceCheck(e){let a=[];if(e.framework.includes("CIS"))a.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})),a.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 a}createComplianceCheck(e){let a=`check-${Date.now()}-${this.checkCounter++}`,r={id:a,...e};return this.complianceChecks.set(a,r),r}assessSecurityPosture(e){let a=`posture-${Date.now()}-${this.postureCounter++}`,r=Array.from(this.complianceChecks.values()),n=r.filter((d)=>d.status==="PASS").length,i=r.length,o=i>0?Math.round(n/i*100):0,c;if(o>=90)c="A";else if(o>=80)c="B";else if(o>=70)c="C";else if(o>=60)c="D";else c="F";let u={id:a,accountId:e.accountId,region:e.region,score:o,grade:c,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(a,u),u}getScan(e){return this.scans.get(e)}listScans(){return Array.from(this.scans.values())}getOpenFindings(e){return Array.from(this.findings.values()).filter((a)=>a.status==="OPEN"&&(!e||a.severity===e))}getComplianceChecksByStatus(e){return Array.from(this.complianceChecks.values()).filter((a)=>a.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 Cf=new hl;class yl{configs=new Map;results=new Map;policies=new Map;configCounter=0;resultCounter=0;policyCounter=0;configureScan(e){let a=`scan-config-${Date.now()}-${this.configCounter++}`,r={id:a,...e};return this.configs.set(a,r),r}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 a=this.configs.get(e);if(!a)throw Error(`Scan config not found: ${e}`);let r=`${a.repository}:${a.imageTag}`;console.log(`
|
|
3782
3782
|
Scanning image: ${r}`),console.log(`Scanner: ${a.scanner}`);let n=`scan-result-${Date.now()}-${this.resultCounter++}`,i=this.simulateVulnerabilities(a),o={total:i.length,critical:i.filter((d)=>d.severity==="CRITICAL").length,high:i.filter((d)=>d.severity==="HIGH").length,medium:i.filter((d)=>d.severity==="MEDIUM").length,low:i.filter((d)=>d.severity==="LOW").length,unknown:i.filter((d)=>d.severity==="UNKNOWN").length},c=this.evaluateScanResult(a,o),u={id:n,imageUri:r,scannerType:a.scanner,scanDate:new Date,vulnerabilities:i,summary:o,passed:c};return this.results.set(n,u),console.log(`
|
|
3783
|
-
Scan Results:`),console.log(` Total vulnerabilities: ${o.total}`),console.log(` Critical: ${o.critical}`),console.log(` High: ${o.high}`),console.log(` Medium: ${o.medium}`),console.log(` Low: ${o.low}`),console.log(` Status: ${c?"✓ PASSED":"✗ FAILED"}`),u}simulateVulnerabilities(e){let a=[];if(e.scanner==="trivy"||e.scanner==="ecr")a.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}),a.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 a}evaluateScanResult(e,a){if(!e.failOnSeverity)return!0;switch(e.failOnSeverity){case"CRITICAL":return a.critical===0;case"HIGH":return a.critical===0&&a.high===0;case"MEDIUM":return a.critical===0&&a.high===0&&a.medium===0;case"LOW":return a.total===0;default:return!0}}createPolicy(e){let a=`policy-${Date.now()}-${this.policyCounter++}`,r={id:a,...e};return this.policies.set(a,r),r}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: ${o.total}`),console.log(` Critical: ${o.critical}`),console.log(` High: ${o.high}`),console.log(` Medium: ${o.medium}`),console.log(` Low: ${o.low}`),console.log(` Status: ${c?"✓ PASSED":"✗ FAILED"}`),u}simulateVulnerabilities(e){let a=[];if(e.scanner==="trivy"||e.scanner==="ecr")a.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}),a.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 a}evaluateScanResult(e,a){if(!e.failOnSeverity)return!0;switch(e.failOnSeverity){case"CRITICAL":return a.critical===0;case"HIGH":return a.critical===0&&a.high===0;case"MEDIUM":return a.critical===0&&a.high===0&&a.medium===0;case"LOW":return a.total===0;default:return!0}}createPolicy(e){let a=`policy-${Date.now()}-${this.policyCounter++}`,r={id:a,...e};return this.policies.set(a,r),r}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 wf=new yl;class Sl{configs=new Map;multiStageConfigs=new Map;optimizations=new Map;analyses=new Map;configCounter=0;multiStageCounter=0;optimizationCounter=0;analysisCounter=0;createBuildConfig(e){let a=`build-config-${Date.now()}-${this.configCounter++}`,r={id:a,...e};return this.configs.set(a,r),r}createOptimizedBuildConfig(e){let a={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:a,buildArgs:{BUILDKIT_INLINE_CACHE:"1"}})}createMultiStageConfig(e){let a=`multi-stage-${Date.now()}-${this.multiStageCounter++}`,r={id:a,...e};return this.multiStageConfigs.set(a,r),r}createNodeMultiStageBuild(e){let a=e.nodeVersion||"18-alpine";return this.createMultiStageConfig({name:e.name,targetStage:e.targetStage||"production",stages:[{name:"dependencies",baseImage:`node:${a}`,workdir:"/app",commands:["COPY package*.json ./","RUN npm ci --only=production"]},{name:"build",baseImage:`node:${a}`,workdir:"/app",commands:["COPY package*.json ./","RUN npm ci","COPY . .","RUN npm run build"]},{name:"production",baseImage:`node:${a}`,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 a=this.multiStageConfigs.get(e);if(!a)throw Error(`Multi-stage config not found: ${e}`);let r=[];for(let n of a.stages){if(r.push(`# Stage: ${n.name}`),r.push(`FROM ${n.baseImage} AS ${n.name}`),n.workdir)r.push(`WORKDIR ${n.workdir}`);if(n.env)for(let[i,o]of Object.entries(n.env))r.push(`ENV ${i}=${o}`);for(let i of n.commands)r.push(i);r.push("")}return r.join(`
|
|
3784
3784
|
`)}analyzeImage(e,a){let r=`analysis-${Date.now()}-${this.analysisCounter++}`,n=a.map((u)=>({...u,cacheable:this.isLayerCacheable(u.command)})),i=n.reduce((u,d)=>u+d.size,0),o=n.filter((u)=>!u.cacheable&&u.size>100).length,c={id:r,imageId:e,layers:n,totalSize:i,unnecessaryLayers:o};return this.analyses.set(r,c),c}isLayerCacheable(e){let a=["FROM","RUN","COPY","ADD","WORKDIR","ENV"],r=["CMD","ENTRYPOINT","LABEL"];for(let n of a)if(e.startsWith(n))return!0;for(let n of r)if(e.startsWith(n))return!1;return!1}generateOptimizations(e){let a=this.analyses.get(e);if(!a)throw Error(`Analysis not found: ${e}`);let r=`optimization-${Date.now()}-${this.optimizationCounter++}`,n=[],i=a.layers.filter((m)=>m.command.startsWith("RUN"));if(i.length>5)n.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 o=a.layers[0];if(o.command.includes("ubuntu")||o.command.includes("debian"))n.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 c=a.layers.filter((m)=>m.command.startsWith("COPY"));if(c.length>0&&c[0].index>3)n.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 u={sizeBefore:a.totalSize,sizeAfter:a.totalSize*0.6,timeBefore:300,timeAfter:120},d={id:r,name:`Optimization for ${a.imageId}`,recommendations:n,estimatedSavings:u};return this.optimizations.set(r,d),d}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 Af=new Sl;class bl{registries=new Map;credentials=new Map;registryCounter=0;credentialsCounter=0;createRegistry(e){let a=`registry-${Date.now()}-${this.registryCounter++}`,r={id:a,...e};return this.registries.set(a,r),r}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 a=this.createECRRepository({name:e.name,region:e.region,scanOnPush:!0,encryption:"KMS"});return a.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"}}]},a}enableReplication(e,a){let r=this.registries.get(e);if(!r)throw Error(`Registry not found: ${e}`);return r.replication={enabled:!0,destinations:a},r}createCredentials(e){let a=`creds-${Date.now()}-${this.credentialsCounter++}`,r={id:a,...e};return this.credentials.set(a,r),r}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((a)=>({Destinations:[{Region:a.region,...a.registryId&&{RegistryId:a.registryId}}]}))}}}}clear(){this.registries.clear(),this.credentials.clear(),this.registryCounter=0,this.credentialsCounter=0}}var If=new bl;class vl{meshes=new Map;virtualNodes=new Map;virtualRouters=new Map;virtualGateways=new Map;meshCounter=0;nodeCounter=0;routerCounter=0;gatewayCounter=0;createMesh(e){let a=`mesh-${Date.now()}-${this.meshCounter++}`,r={id:a,...e};return this.meshes.set(a,r),r}createAppMesh(e){return this.createMesh({name:e.name,meshType:"app_mesh",services:e.services,virtualNodes:[],virtualRouters:[],virtualGateways:[]})}createVirtualNode(e){let a=`vnode-${Date.now()}-${this.nodeCounter++}`,r={id:a,...e};return this.virtualNodes.set(a,r),r}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 a=`vrouter-${Date.now()}-${this.routerCounter++}`,r={id:a,...e};return this.virtualRouters.set(a,r),r}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 a=`vgateway-${Date.now()}-${this.gatewayCounter++}`,r={id:a,...e};return this.virtualGateways.set(a,r),r}createIngressGateway(e){let a={port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3}};if(e.enableTLS&&e.certificateArn)a.tls={mode:"STRICT",certificate:{acm:e.certificateArn}};return this.createVirtualGateway({name:e.name,listeners:[a],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,a){return{Type:"AWS::AppMesh::VirtualNode",Properties:{MeshName:a,VirtualNodeName:e.name,Spec:{Listeners:e.listeners.map((r)=>({PortMapping:{Port:r.port,Protocol:r.protocol},...r.healthCheck&&{HealthCheck:{Protocol:r.healthCheck.protocol,...r.healthCheck.path&&{Path:r.healthCheck.path},IntervalMillis:r.healthCheck.interval*1000,TimeoutMillis:r.healthCheck.timeout*1000,HealthyThreshold:r.healthCheck.healthyThreshold,UnhealthyThreshold:r.healthCheck.unhealthyThreshold}}})),ServiceDiscovery:{AWSCloudMap:{NamespaceName:e.serviceDiscovery.namespace,ServiceName:e.serviceDiscovery.serviceName}}}}}}generateVirtualRouterCF(e,a){return{Type:"AWS::AppMesh::VirtualRouter",Properties:{MeshName:a,VirtualRouterName:e.name,Spec:{Listeners:e.listeners.map((r)=>({PortMapping:{Port:r.port,Protocol:r.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 Rf=new vl;class Tl{layers=new Map;versions=new Map;permissions=new Map;layerCounter=0;versionCounter=0;permissionCounter=0;createLayer(e){let a=`layer-${Date.now()}-${this.layerCounter++}`,r=1,n={id:a,layerArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:1`,version:1,...e};return this.layers.set(a,n),n}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 a=this.layers.get(e);if(!a)throw Error(`Layer not found: ${e}`);let r=`version-${Date.now()}-${this.versionCounter++}`,n=a.version+1,i={id:r,layerName:a.layerName,version:n,createdAt:new Date,compatibleRuntimes:a.compatibleRuntimes,size:a.size,codeHash:this.generateHash()};return this.versions.set(r,i),a.version=n,a.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${a.layerName}:${n}`,i}addPermission(e){let a=`permission-${Date.now()}-${this.permissionCounter++}`,r={id:a,layerName:e.layerName,version:e.version,principal:e.principal,action:"lambda:GetLayerVersion",organizationId:e.organizationId};return this.permissions.set(a,r),r}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((a)=>a.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 Pf=new Tl;class El{versions=new Map;aliases=new Map;deployments=new Map;versionCounter=0;aliasCounter=0;deploymentCounter=0;publishVersion(e){let a=`version-${Date.now()}-${this.versionCounter++}`,r=this.getNextVersionNumber(e.functionName),n={id:a,functionName:e.functionName,version:r.toString(),functionArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${r}`,codeHash:this.generateHash(),description:e.description,runtime:e.runtime,memorySize:e.memorySize,timeout:e.timeout,publishedAt:new Date};return this.versions.set(a,n),n}getNextVersionNumber(e){let a=Array.from(this.versions.values()).filter((r)=>r.functionName===e).map((r)=>parseInt(r.version));return a.length>0?Math.max(...a)+1:1}createAlias(e){let a=`alias-${Date.now()}-${this.aliasCounter++}`,r={id:a,aliasArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${e.aliasName}`,revisionId:this.generateHash(),...e};return this.aliases.set(a,r),r}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,a){let r=this.aliases.get(e);if(!r)throw Error(`Alias not found: ${e}`);return r.functionVersion=a,r.revisionId=this.generateHash(),r}configureWeightedRouting(e,a){let r=this.aliases.get(e);if(!r)throw Error(`Alias not found: ${e}`);return r.routingConfig={additionalVersionWeights:a},r}createCanaryDeployment(e){let a=`deployment-${Date.now()}-${this.deploymentCounter++}`,r=Array.from(this.aliases.values()).find((i)=>i.functionName===e.functionName&&i.aliasName===e.aliasName);if(!r)r=this.createAlias({functionName:e.functionName,aliasName:e.aliasName,functionVersion:e.fromVersion});this.configureWeightedRouting(r.id,{[e.toVersion]:e.canaryWeight});let n={id:a,functionName:e.functionName,fromVersion:e.fromVersion,toVersion:e.toVersion,aliasName:e.aliasName,strategy:"canary",status:"in_progress",startedAt:new Date};return this.deployments.set(a,n),n}completeDeployment(e){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);let r=Array.from(this.aliases.values()).find((n)=>n.functionName===a.functionName&&n.aliasName===a.aliasName);if(r)r.functionVersion=a.toVersion,r.routingConfig=void 0;return a.status="completed",a.completedAt=new Date,a}rollbackDeployment(e){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);let r=Array.from(this.aliases.values()).find((n)=>n.functionName===a.functionName&&n.aliasName===a.aliasName);if(r)r.functionVersion=a.fromVersion,r.routingConfig=void 0;return a.status="failed",a.completedAt=new Date,a}generateHash(){return Math.random().toString(36).substring(2,15)}getVersion(e){return this.versions.get(e)}listVersions(e){let a=Array.from(this.versions.values());return e?a.filter((r)=>r.functionName===e):a}getAlias(e){return this.aliases.get(e)}listAliases(e){let a=Array.from(this.aliases.values());return e?a.filter((r)=>r.functionName===e):a}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(([a,r])=>({FunctionVersion:a,FunctionWeight:r}))}}}}}clear(){this.versions.clear(),this.aliases.clear(),this.deployments.clear(),this.versionCounter=0,this.aliasCounter=0,this.deploymentCounter=0}}var Nf=new El;class wl{configs=new Map;provisionedConfigs=new Map;schedules=new Map;autoScalingConfigs=new Map;configCounter=0;provisionedCounter=0;scheduleCounter=0;autoScalingCounter=0;setReservedConcurrency(e){let a=`concurrency-${Date.now()}-${this.configCounter++}`,r={id:a,functionName:e.functionName,reservedConcurrency:e.reservedConcurrency};return this.configs.set(a,r),r}setProvisionedConcurrency(e){let a=`provisioned-${Date.now()}-${this.provisionedCounter++}`,r={id:a,functionName:e.functionName,qualifier:e.qualifier,provisionedConcurrentExecutions:e.provisionedConcurrentExecutions,status:"pending",lastModified:new Date};return this.provisionedConfigs.set(a,r),setTimeout(()=>{r.status="ready",r.allocatedConcurrency=e.provisionedConcurrentExecutions,r.availableConcurrency=e.provisionedConcurrentExecutions},100),r}configureWarmPool(e){return this.setProvisionedConcurrency({functionName:e.functionName,qualifier:e.alias,provisionedConcurrentExecutions:e.minInstances})}createSchedule(e){let a=`schedule-${Date.now()}-${this.scheduleCounter++}`,r={id:a,...e};return this.schedules.set(a,r),r}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 a=`autoscaling-${Date.now()}-${this.autoScalingCounter++}`,r={id:a,...e};return this.autoScalingConfigs.set(a,r),r}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 Df=new wl;class Cl{destinations=new Map;records=new Map;eventBridgeDestinations=new Map;destinationCounter=0;recordCounter=0;eventBridgeCounter=0;configureDestinations(e){let a=`destination-${Date.now()}-${this.destinationCounter++}`,r={id:a,...e};return this.destinations.set(a,r),r}configureSQSDestination(e){let a={type:"sqs",arn:e.queueArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?a:void 0,failureDestination:e.onFailure?a:void 0,maxEventAge:21600,maxRetries:2})}configureSNSDestination(e){let a={type:"sns",arn:e.topicArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?a:void 0,failureDestination:e.onFailure?a:void 0,maxEventAge:21600,maxRetries:2})}configureEventBridgeDestination(e){let a={type:"eventbridge",arn:e.eventBusArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?a:void 0,failureDestination:e.onFailure?a:void 0,maxEventAge:21600,maxRetries:2})}configureLambdaDestination(e){let a={type:"lambda",arn:e.destinationFunctionArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?a:void 0,failureDestination:e.onFailure?a: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 a=`eventbridge-${Date.now()}-${this.eventBridgeCounter++}`,r={id:a,functionName:e.functionName,eventBusArn:e.eventBusArn,detailType:e.detailType||"Lambda Function Invocation Result",source:e.source||`lambda.${e.functionName}`};return this.eventBridgeDestinations.set(a,r),r}sendToDestination(e){let a=Array.from(this.destinations.values()).find((o)=>o.functionName===e.functionName);if(!a)return null;let r=e.status==="success"?a.successDestination:a.failureDestination;if(!r)return null;let n=`record-${Date.now()}-${this.recordCounter++}`,i={id:n,timestamp:new Date,functionName:e.functionName,requestId:e.requestId,status:e.status,destinationType:r.type,destinationArn:r.arn,payload:e.payload,error:e.error};return this.records.set(n,i),i}getDestination(e){return this.destinations.get(e)}listDestinations(e){let a=Array.from(this.destinations.values());return e?a.filter((r)=>r.functionName===e):a}getDestinationRecords(e){let a=Array.from(this.records.values());return e?a.filter((r)=>r.functionName===e):a}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 kf=new Cl;class Al{vpcConfigs=new Map;endpoints=new Map;networkInterfaces=new Map;connectivity=new Map;configCounter=0;endpointCounter=0;eniCounter=0;connectivityCounter=0;configureVPC(e){let a=`vpc-config-${Date.now()}-${this.configCounter++}`,r={id:a,...e};this.vpcConfigs.set(a,r);for(let n of e.subnetIds)this.createNetworkInterface({functionName:e.functionName,subnetId:n});return r}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 a=`endpoint-${Date.now()}-${this.endpointCounter++}`,r={id:a,...e};return this.endpoints.set(a,r),r}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 a=`eni-${Date.now()}-${this.eniCounter++}`,r={id:a,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(a,r),setTimeout(()=>{r.status="available"},100),r}analyzeConnectivity(e){let a=`connectivity-${Date.now()}-${this.connectivityCounter++}`,r=Array.from(this.vpcConfigs.values()).find((d)=>d.functionName===e.functionName),n=Array.from(this.endpoints.values()).filter((d)=>d.vpcId===r?.vpcId).map((d)=>d.serviceName),i=[],o=e.hasNATGateway??!1,c=e.hasInternetGateway??!1;if(!o&&!c)i.push("Add NAT Gateway for internet access");if(!n.includes("com.amazonaws.us-east-1.s3"))i.push("Add S3 VPC endpoint to reduce NAT costs");if(!n.includes("com.amazonaws.us-east-1.dynamodb"))i.push("Add DynamoDB VPC endpoint for private access");let u={id:a,functionName:e.functionName,hasInternetAccess:o||c,hasNATGateway:o,hasVPCEndpoints:n.length>0,endpoints:n,recommendations:i};return this.connectivity.set(a,u),u}getVPCConfig(e){return this.vpcConfigs.get(e)}listVPCConfigs(e){let a=Array.from(this.vpcConfigs.values());return e?a.filter((r)=>r.functionName===e):a}getNetworkInterfaces(e){return Array.from(this.networkInterfaces.values()).filter((a)=>a.functionName===e)}listVPCEndpoints(e){let a=Array.from(this.endpoints.values());return e?a.filter((r)=>r.vpcId===e):a}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((a)=>({IpProtocol:a.protocol,FromPort:a.fromPort,ToPort:a.toPort,...a.cidrIp&&{CidrIp:a.cidrIp},...a.sourceSecurityGroupId&&{SourceSecurityGroupId:a.sourceSecurityGroupId}}))},...e.egressRules&&{SecurityGroupEgress:e.egressRules.map((a)=>({IpProtocol:a.protocol,FromPort:a.fromPort,ToPort:a.toPort,CidrIp:a.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 _f=new Al;class Il{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(e){let a=`dlq-${Date.now()}-${this.configCounter++}`,r={id:a,...e};return this.dlqConfigs.set(a,r),r}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 a=this.configureSQSDLQ({functionName:e.functionName,queueArn:e.queueArn});return this.createDLQAlarm({dlqConfigId:a.id,alarmName:`${e.functionName}-dlq-alarm`,threshold:e.alarmThreshold,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0}),a}sendToDLQ(e){let a=`message-${Date.now()}-${this.messageCounter++}`,r={id:a,timestamp:new Date,...e};return this.messages.set(a,r),r}createDLQAlarm(e){let a=`alarm-${Date.now()}-${this.alarmCounter++}`,r={id:a,...e};return this.alarms.set(a,r),r}createAgeAlarm(e){let a=this.dlqConfigs.get(e.dlqConfigId);if(!a)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:e.dlqConfigId,alarmName:`${a.functionName}-dlq-age-alarm`,threshold:e.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0})}async reprocessMessage(e){let a=this.messages.get(e);if(!a)throw Error(`Message not found: ${e}`);let r=Array.from(this.dlqConfigs.values()).find((o)=>o.functionName===a.functionName);if(!r)throw Error(`DLQ config not found for function: ${a.functionName}`);let n=`reprocess-${Date.now()}-${this.reprocessCounter++}`,i={id:n,dlqConfigId:r.id,messageId:e,status:"pending",startedAt:new Date};return this.reprocessing.set(n,i),setTimeout(()=>{i.status="processing",setTimeout(()=>{let o=Math.random()>0.3;if(i.status=o?"success":"failed",i.completedAt=new Date,!o)i.error="Reprocessing failed - same error occurred";else this.messages.delete(e)},100)},50),i}async batchReprocess(e){let a=this.dlqConfigs.get(e.dlqConfigId);if(!a)throw Error(`DLQ config not found: ${e.dlqConfigId}`);let r=Array.from(this.messages.values()).filter((n)=>n.functionName===a.functionName).slice(0,e.maxMessages||10).map((n)=>this.reprocessMessage(n.id));return Promise.all(r)}getDLQStats(e){let a=this.dlqConfigs.get(e);if(!a)throw Error(`DLQ config not found: ${e}`);let r=Array.from(this.messages.values()).filter((c)=>c.functionName===a.functionName),n={},i=0;for(let c of r)n[c.errorType]=(n[c.errorType]||0)+1,i+=c.attemptCount;let o=r.map((c)=>c.timestamp);return{totalMessages:r.length,oldestMessage:o.length>0?new Date(Math.min(...o.map((c)=>c.getTime()))):void 0,newestMessage:o.length>0?new Date(Math.max(...o.map((c)=>c.getTime()))):void 0,averageAttempts:r.length>0?i/r.length:0,errorTypes:n}}getDLQConfig(e){return this.dlqConfigs.get(e)}listDLQConfigs(){return Array.from(this.dlqConfigs.values())}getDLQMessages(e){let a=this.dlqConfigs.get(e);if(!a)return[];return Array.from(this.messages.values()).filter((r)=>r.functionName===a.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 a=this.dlqConfigs.get(e.dlqConfigId);if(!a)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`DLQ alarm for ${a.functionName}`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:e.evaluationPeriods,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:a.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 xf=new Il;class Rl{policies=new Map;healthChecks=new Map;trafficPolicies=new Map;policyCounter=0;healthCheckCounter=0;trafficPolicyCounter=0;createWeightedPolicy(e){let a=`policy-${Date.now()}-${this.policyCounter++}`,r={id:a,type:"weighted",...e};return this.policies.set(a,r),r}createLatencyPolicy(e){let a=`policy-${Date.now()}-${this.policyCounter++}`,r={id:a,type:"latency",...e};return this.policies.set(a,r),r}createFailoverPolicy(e){let a=`policy-${Date.now()}-${this.policyCounter++}`,r={id:a,type:"failover",...e};return this.policies.set(a,r),r}createGeolocationPolicy(e){let a=`policy-${Date.now()}-${this.policyCounter++}`,r={id:a,type:"geolocation",...e};return this.policies.set(a,r),r}createGeoproximityPolicy(e){let a=`policy-${Date.now()}-${this.policyCounter++}`,r={id:a,type:"geoproximity",...e};return this.policies.set(a,r),r}createHTTPHealthCheck(e){let a=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:a,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(a,r),setTimeout(()=>{r.healthCheckStatus=Math.random()>0.2?"Healthy":"Unhealthy"},100),r}createTCPHealthCheck(e){let a=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:a,type:"tcp",fullyQualifiedDomainName:e.ipAddress,requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(a,r),setTimeout(()=>{r.healthCheckStatus=Math.random()>0.1?"Healthy":"Unhealthy"},100),r}createCalculatedHealthCheck(e){let a=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:a,type:"calculated",requestInterval:30,failureThreshold:0,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(a,r),setTimeout(()=>{let n=e.childHealthChecks.filter((i)=>this.healthChecks.get(i)?.healthCheckStatus==="Healthy").length;r.healthCheckStatus=n>=e.healthThreshold?"Healthy":"Unhealthy"},150),r}createTrafficPolicy(e){let a=`traffic-policy-${Date.now()}-${this.trafficPolicyCounter++}`,r={id:a,version:1,...e};return this.trafficPolicies.set(a,r),r}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 a={},r=[];return e.locations.forEach((n,i)=>{let o=`endpoint${i}`;a[o]={type:"value",value:n.endpoint},r.push({endpointReference:o,region:n.region,latitude:n.latitude,longitude:n.longitude,bias:n.bias})}),this.createTrafficPolicy({name:e.name,document:{recordType:"A",startRule:"geoproximity",endpoints:a,rules:{geoproximity:{ruleType:"geoproximity",locations:r}}}})}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 a={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 r=e;a.Properties.HealthCheckConfig.ChildHealthChecks=r.childHealthChecks,a.Properties.HealthCheckConfig.HealthThreshold=r.healthThreshold}else{if(e.ipAddress)a.Properties.HealthCheckConfig.IPAddress=e.ipAddress;if(e.fullyQualifiedDomainName)a.Properties.HealthCheckConfig.FullyQualifiedDomainName=e.fullyQualifiedDomainName;if(e.port)a.Properties.HealthCheckConfig.Port=e.port;if(e.resourcePath)a.Properties.HealthCheckConfig.ResourcePath=e.resourcePath;if(e.enableSNI)a.Properties.HealthCheckConfig.EnableSNI=!0}return a}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 $f=new Rl;class Pl{configs=new Map;ksks=new Map;validations=new Map;configCounter=0;kskCounter=0;validationCounter=0;enableDNSSEC(e){let a=`dnssec-${Date.now()}-${this.configCounter++}`,r={id:a,hostedZoneId:e.hostedZoneId,status:"SIGNING",signingStatus:"Initializing DNSSEC signing"};if(this.configs.set(a,r),e.kmsKeyArn)this.createKSK({name:`ksk-${e.hostedZoneId}`,hostedZoneId:e.hostedZoneId,kmsKeyArn:e.kmsKeyArn});return setTimeout(()=>{r.status="SIGNED",r.signingStatus="DNSSEC signing complete"},100),r}disableDNSSEC(e){let a=this.configs.get(e);if(!a)throw Error(`DNSSEC config not found: ${e}`);return a.status="DELETING",a.signingStatus="Removing DNSSEC signing",setTimeout(()=>{a.status="NOT_SIGNING",a.signingStatus="DNSSEC signing removed"},100),a}createKSK(e){let a=`ksk-${Date.now()}-${this.kskCounter++}`,r={id:a,status:"ACTIVE",flag:257,keyManagementServiceArn:e.kmsKeyArn,digestAlgorithm:2,keyTag:Math.floor(Math.random()*65535),publicKey:this.generatePublicKey(),...e};r.dnskeyRecord=`${r.flag} 3 8 ${r.publicKey}`;let n=this.generateDigest(r.dnskeyRecord);return r.digestValue=n,r.dsRecord=`${r.keyTag} 8 ${r.digestAlgorithm} ${n}`,this.ksks.set(a,r),r}deactivateKSK(e){let a=this.ksks.get(e);if(!a)throw Error(`KSK not found: ${e}`);return a.status="INACTIVE",a}validateDNSSEC(e){let a=`validation-${Date.now()}-${this.validationCounter++}`,r=e.checkDNSKEY!==!1?Math.random()>0.1:!1,n=e.checkRRSIG!==!1?Math.random()>0.1:!1,i=r&&n,o=[];if(!r)o.push("DNSKEY record not found");if(!n)o.push("RRSIG record not found");let c;if(!r&&!n)c="INSECURE";else if(r&&n&&i)c="VALID";else if(r||n)c="BOGUS",o.push("Invalid signature or incomplete DNSSEC chain");else c="INVALID";let u={id:a,domain:e.domain,validationStatus:c,dnskeyPresent:r,rrsigPresent:n,validSignature:i,errors:o};return this.validations.set(a,u),u}getDNSSECConfig(e){return this.configs.get(e)}listDNSSECConfigs(){return Array.from(this.configs.values())}getKSK(e){return this.ksks.get(e)}listKSKs(e){let a=Array.from(this.ksks.values());return e?a.filter((r)=>r.hostedZoneId===e):a}getDSRecord(e){let a=this.ksks.get(e);if(!a||!a.dsRecord)throw Error("DS record not available");return a.dsRecord}generatePublicKey(){let e="";for(let a=0;a<256;a++)e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return e}generateDigest(e){let a="";for(let r=0;r<64;r++)a+="0123456789ABCDEF".charAt(Math.floor(Math.random()*16));return a}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 Of=new Pl;class Nl{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 a=`endpoint-${Date.now()}-${this.endpointCounter++}`,r={id:a,status:"CREATING",...e};return this.endpoints.set(a,r),setTimeout(()=>{r.status="OPERATIONAL",r.ipAddresses.forEach((n)=>{if(!n.ip)n.ip=`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`})},100),r}createInboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"INBOUND",ipAddresses:e.subnetIds.map((a)=>({subnetId:a})),securityGroupIds:e.securityGroupIds})}createOutboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"OUTBOUND",ipAddresses:e.subnetIds.map((a)=>({subnetId:a})),securityGroupIds:e.securityGroupIds})}createResolverRule(e){let a=`rule-${Date.now()}-${this.ruleCounter++}`,r={id:a,status:"CREATING",...e};return this.rules.set(a,r),setTimeout(()=>{r.status="COMPLETE"},100),r}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 a=`domain-list-${Date.now()}-${this.domainListCounter++}`,r={id:a,status:"CREATING",...e};return this.domainLists.set(a,r),setTimeout(()=>{r.status="COMPLETE"},100),r}createFirewallRuleGroup(e){let a=`rule-group-${Date.now()}-${this.ruleGroupCounter++}`,r={id:a,name:e.name,rules:e.rules.map((n,i)=>({id:`rule-${a}-${i}`,...n})),shareStatus:"NOT_SHARED"};return this.ruleGroups.set(a,r),r}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 a=`firewall-${Date.now()}-${this.firewallCounter++}`,r={id:a,name:e.name,firewallRuleGroupAssociations:e.ruleGroupAssociations.map((n,i)=>({id:`assoc-${a}-${i}`,vpcId:e.vpcId,firewallRuleGroupId:n.firewallRuleGroupId,priority:n.priority,mutationProtection:n.mutationProtection||"DISABLED",status:"COMPLETE"}))};return this.firewalls.set(a,r),r}createMalwareProtectionFirewall(e){let a=this.createFirewallDomainList({name:`${e.name}-malware-domains`,domains:e.maliciousDomains}),r=this.createBlockRule({name:`${e.name}-block-malware`,priority:100,domainListId:a.id,blockResponse:"NXDOMAIN"});return this.createDNSFirewall({name:e.name,vpcId:e.vpcId,ruleGroupAssociations:[{firewallRuleGroupId:r.id,priority:100,mutationProtection:"ENABLED"}]})}getEndpoint(e){return this.endpoints.get(e)}listEndpoints(e){let a=Array.from(this.endpoints.values());return e?a.filter((r)=>r.direction===e):a}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((a)=>({SubnetId:a.subnetId,...a.ip&&{Ip:a.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((a)=>({Ip:a.ip,Port:a.port||53}))},...e.resolverEndpointId&&{ResolverEndpointId:e.resolverEndpointId}}}}generateFirewallRuleGroupCF(e){return{Type:"AWS::Route53Resolver::FirewallRuleGroup",Properties:{Name:e.name,FirewallRules:e.rules.map((a)=>({Name:a.name,Priority:a.priority,Action:a.action,FirewallDomainListId:a.firewallDomainListId,...a.blockResponse&&{BlockResponse:a.blockResponse},...a.blockOverrideDomain&&{BlockOverrideDomain:a.blockOverrideDomain},...a.blockOverrideTTL&&{BlockOverrideTtl:a.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 Lf=new Nl;class Dl{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 a=`bounce-${Date.now()}-${this.bounceCounter++}`,r={id:a,...e};if(this.bounces.set(a,r),e.bounceType==="Permanent")this.addToSuppressionList({emailAddress:e.recipient,reason:"BOUNCE"});return r}recordComplaint(e){let a=`complaint-${Date.now()}-${this.complaintCounter++}`,r={id:a,...e};this.complaints.set(a,r);for(let n of e.recipients)this.addToSuppressionList({emailAddress:n,reason:"COMPLAINT"});return r}createBounceHandler(e){let a=`handler-${Date.now()}-${this.handlerCounter++}`,r={id:a,...e};return this.handlers.set(a,r),r}createAutomaticBounceHandler(e){return this.createBounceHandler({name:e.name,bounceThreshold:5,complaintThreshold:0.1,suppressionDuration:2592000,autoSuppress:!0,notificationTopicArn:e.notificationTopicArn})}addToSuppressionList(e){let a=`suppression-${Date.now()}-${this.suppressionCounter++}`,r=e.expirationDays?new Date(Date.now()+e.expirationDays*24*60*60*1000):void 0,n={id:a,emailAddress:e.emailAddress,reason:e.reason,suppressedAt:new Date,expiresAt:r,bounceCount:e.reason==="BOUNCE"?1:0,complaintCount:e.reason==="COMPLAINT"?1:0};return this.suppressionList.set(e.emailAddress,n),n}removeFromSuppressionList(e){return this.suppressionList.delete(e)}isSuppressed(e){let a=this.suppressionList.get(e);if(!a)return!1;if(a.expiresAt&&a.expiresAt<new Date)return this.suppressionList.delete(e),!1;return!0}getBounceStatistics(e,a){let r=Array.from(this.bounces.values()).filter((p)=>p.timestamp>=e&&p.timestamp<=a),n=r.length,i=r.filter((p)=>p.bounceType==="Permanent").length,o=r.filter((p)=>p.bounceType==="Transient").length,c=n*10,u=n/c*100,d=new Map;for(let p of r)d.set(p.recipient,(d.get(p.recipient)||0)+1);let m=Array.from(d.entries()).map(([p,g])=>({email:p,count:g})).sort((p,g)=>g.count-p.count).slice(0,10);return{totalBounces:n,permanentBounces:i,transientBounces:o,bounceRate:u,topRecipients:m}}getComplaintStatistics(e,a){let r=Array.from(this.complaints.values()).filter((d)=>d.timestamp>=e&&d.timestamp<=a),n=r.length,i=new Set;for(let d of r)for(let m of d.recipients)i.add(m);let o=i.size,c=n*1000,u=n/c*100;return{totalComplaints:n,uniqueComplainters:o,complaintRate:u}}calculateReputationMetrics(){let e=`metrics-${Date.now()}-${this.metricsCounter++}`,a=new Date,r=new Date(a.getTime()-86400000),n=this.getBounceStatistics(r,a),i=this.getComplaintStatistics(r,a),o;if(n.bounceRate>10||i.complaintRate>0.5)o="Shutdown";else if(n.bounceRate>5||i.complaintRate>0.1)o="Probation";else if(n.bounceRate>2||i.complaintRate>0.05)o="Warning";else o="Good";let c={id:e,timestamp:a,bounceRate:n.bounceRate,complaintRate:i.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:n.totalBounces*10,reputationStatus:o};return this.metrics.set(e,c),c}getBounces(e){let a=Array.from(this.bounces.values());return e?a.filter((r)=>r.messageId===e):a}getComplaints(e){let a=Array.from(this.complaints.values());return e?a.filter((r)=>r.messageId===e):a}listSuppressionList(e){let a=Array.from(this.suppressionList.values());return e?a.filter((r)=>r.reason===e):a}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 Mf=new Dl;class kl{events=new Map;campaigns=new Map;reports=new Map;abTests=new Map;eventCounter=0;campaignCounter=0;reportCounter=0;abTestCounter=0;trackEvent(e){let a=`event-${Date.now()}-${this.eventCounter++}`,r={id:a,...e};if(this.events.set(a,r),e.tags?.campaignId)this.updateCampaignStats(e.tags.campaignId,e.eventType);return r}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 a=`campaign-${Date.now()}-${this.campaignCounter++}`,r={id:a,sentCount:0,deliveredCount:0,openCount:0,clickCount:0,bounceCount:0,complaintCount:0,createdAt:new Date,...e};return this.campaigns.set(a,r),r}updateCampaignStats(e,a){let r=this.campaigns.get(e);if(!r)return;switch(a){case"send":r.sentCount++;break;case"delivery":r.deliveredCount++;break;case"open":r.openCount++;break;case"click":r.clickCount++;break;case"bounce":r.bounceCount++;break;case"complaint":r.complaintCount++;break}}generateReport(e){let a=`report-${Date.now()}-${this.reportCounter++}`,r=Array.from(this.events.values()).filter((v)=>{let N=v.timestamp>=e.startDate&&v.timestamp<=e.endDate,R=!e.campaignId||v.tags?.campaignId===e.campaignId;return N&&R}),n=r.filter((v)=>v.eventType==="send").length,i=r.filter((v)=>v.eventType==="delivery").length,o=r.filter((v)=>v.eventType==="open").length,c=r.filter((v)=>v.eventType==="click").length,u=r.filter((v)=>v.eventType==="bounce").length,d=r.filter((v)=>v.eventType==="complaint").length,m=n>0?i/n*100:0,p=i>0?o/i*100:0,g=i>0?c/i*100:0,h=o>0?c/o*100:0,y=n>0?u/n*100:0,f=i>0?d/i*100:0,b=new Map;for(let v of r)if(v.eventType==="click"){let N=v;b.set(N.link,(b.get(N.link)||0)+1)}let T=Array.from(b.entries()).map(([v,N])=>({link:v,clicks:N})).sort((v,N)=>N.clicks-v.clicks).slice(0,10),w={desktop:0,mobile:0,tablet:0,unknown:0};for(let v of r)if(v.eventType==="open"||v.eventType==="click"){let N=v.userAgent.toLowerCase();if(N.includes("mobile"))w.mobile++;else if(N.includes("tablet"))w.tablet++;else if(N.includes("mozilla"))w.desktop++;else w.unknown++}let I={id:a,campaignId:e.campaignId,startDate:e.startDate,endDate:e.endDate,totalSent:n,totalDelivered:i,totalOpened:o,totalClicked:c,totalBounced:u,totalComplaints:d,deliveryRate:m,openRate:p,clickRate:g,clickToOpenRate:h,bounceRate:y,complaintRate:f,topLinks:T,deviceBreakdown:w,locationBreakdown:{}};return this.reports.set(a,I),I}createABTest(e){let a=`abtest-${Date.now()}-${this.abTestCounter++}`,r={id:a,name:e.name,variants:e.variants.map((n,i)=>({id:`variant-${a}-${i}`,sentCount:0,openCount:0,clickCount:0,conversionCount:0,...n})),status:"draft"};return this.abTests.set(a,r),r}startABTest(e){let a=this.abTests.get(e);if(!a)throw Error(`A/B test not found: ${e}`);return a.status="running",a.startedAt=new Date,a}completeABTest(e){let a=this.abTests.get(e);if(!a)throw Error(`A/B test not found: ${e}`);let r=a.variants[0],n=0;for(let i of a.variants){let o=i.sentCount>0?i.openCount/i.sentCount:0;if(o>n)n=o,r=i}return a.status="completed",a.completedAt=new Date,a.winner=r.id,a}getCampaign(e){return this.campaigns.get(e)}listCampaigns(){return Array.from(this.campaigns.values())}getEvents(e){let a=Array.from(this.events.values());if(e?.messageId)a=a.filter((r)=>r.messageId===e.messageId);if(e?.eventType)a=a.filter((r)=>r.eventType===e.eventType);if(e?.startDate)a=a.filter((r)=>r.timestamp>=e.startDate);if(e?.endDate)a=a.filter((r)=>r.timestamp<=e.endDate);return a}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 Uf=new kl;class _l{dashboards=new Map;warmupPlans=new Map;domainReputations=new Map;dashboardCounter=0;warmupCounter=0;domainCounter=0;getReputationDashboard(){let e=`dashboard-${Date.now()}-${this.dashboardCounter++}`,a=Math.random()*5,r=Math.random()*0.5,n=Math.floor(Math.random()*10),i=Math.max(0,100-a*10-r*100-n*2),o=[];if(a>2)o.push("Reduce bounce rate by cleaning email list");if(r>0.1)o.push("Review email content and unsubscribe process");if(n>5)o.push("Improve email relevance and targeting");let c={id:e,timestamp:new Date,overallScore:i,bounceRate:a,complaintRate:r,spamReports:n,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:o};return this.dashboards.set(e,c),c}checkBlacklists(){return["Spamhaus ZEN","Spamcop","SORBS","Barracuda","URIBL"].map((e)=>({listName:e,listed:Math.random()>0.95,delistUrl:`https://www.${e.toLowerCase().replace(/\s/g,"")}.org/delist`}))}createWarmupPlan(e){let a=`warmup-${Date.now()}-${this.warmupCounter++}`,r=[],n=(e.targetDailyLimit-e.initialDailyLimit)/e.durationDays;for(let o=0;o<e.durationDays;o++)r.push(Math.floor(e.initialDailyLimit+n*o));let i={id:a,name:e.name,startDate:new Date,currentDay:1,totalDays:e.durationDays,dailyLimits:r,currentLimit:r[0],status:"active"};return this.warmupPlans.set(a,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 a=this.warmupPlans.get(e);if(!a)throw Error(`Warmup plan not found: ${e}`);if(a.currentDay<a.totalDays)a.currentDay++,a.currentLimit=a.dailyLimits[a.currentDay-1];if(a.currentDay>=a.totalDays)a.status="completed";return a}trackDomainReputation(e){let a=`domain-${Date.now()}-${this.domainCounter++}`,r=e.delivered/e.totalSent*100,n=e.delivered>0?e.opened/e.delivered*100:0,i=e.delivered>0?e.clicked/e.delivered*100:0,o=e.bounced/e.totalSent*100,c=e.delivered>0?e.complained/e.delivered*100:0,u=n*0.4+i*0.6,d=Math.max(0,100-o*10-c*100+u*0.2),m={id:a,domain:e.domain,reputationScore:d,totalSent:e.totalSent,deliveryRate:r,openRate:n,clickRate:i,bounceRate:o,complaintRate:c,engagementScore:u};return this.domainReputations.set(e.domain,m),m}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 Bf=new _l;class xl{templates=new Map;versions=new Map;tests=new Map;templateCounter=0;testCounter=0;createTemplate(e){let a=`template-${Date.now()}-${this.templateCounter++}`,r=this.extractVariables(e.subject+e.htmlPart+e.textPart),n={id:a,variables:r,createdAt:new Date,updatedAt:new Date,version:1,...e};return this.templates.set(a,n),this.addVersion({templateId:a,version:1,subject:e.subject,htmlPart:e.htmlPart,textPart:e.textPart,createdBy:"system"}),n}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 u={sizeBefore:a.totalSize,sizeAfter:a.totalSize*0.6,timeBefore:300,timeAfter:120},d={id:r,name:`Optimization for ${a.imageId}`,recommendations:n,estimatedSavings:u};return this.optimizations.set(r,d),d}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 Af=new Sl;class bl{registries=new Map;credentials=new Map;registryCounter=0;credentialsCounter=0;createRegistry(e){let a=`registry-${Date.now()}-${this.registryCounter++}`,r={id:a,...e};return this.registries.set(a,r),r}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 a=this.createECRRepository({name:e.name,region:e.region,scanOnPush:!0,encryption:"KMS"});return a.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"}}]},a}enableReplication(e,a){let r=this.registries.get(e);if(!r)throw Error(`Registry not found: ${e}`);return r.replication={enabled:!0,destinations:a},r}createCredentials(e){let a=`creds-${Date.now()}-${this.credentialsCounter++}`,r={id:a,...e};return this.credentials.set(a,r),r}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((a)=>({Destinations:[{Region:a.region,...a.registryId&&{RegistryId:a.registryId}}]}))}}}}clear(){this.registries.clear(),this.credentials.clear(),this.registryCounter=0,this.credentialsCounter=0}}var If=new bl;class vl{meshes=new Map;virtualNodes=new Map;virtualRouters=new Map;virtualGateways=new Map;meshCounter=0;nodeCounter=0;routerCounter=0;gatewayCounter=0;createMesh(e){let a=`mesh-${Date.now()}-${this.meshCounter++}`,r={id:a,...e};return this.meshes.set(a,r),r}createAppMesh(e){return this.createMesh({name:e.name,meshType:"app_mesh",services:e.services,virtualNodes:[],virtualRouters:[],virtualGateways:[]})}createVirtualNode(e){let a=`vnode-${Date.now()}-${this.nodeCounter++}`,r={id:a,...e};return this.virtualNodes.set(a,r),r}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 a=`vrouter-${Date.now()}-${this.routerCounter++}`,r={id:a,...e};return this.virtualRouters.set(a,r),r}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 a=`vgateway-${Date.now()}-${this.gatewayCounter++}`,r={id:a,...e};return this.virtualGateways.set(a,r),r}createIngressGateway(e){let a={port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3}};if(e.enableTLS&&e.certificateArn)a.tls={mode:"STRICT",certificate:{acm:e.certificateArn}};return this.createVirtualGateway({name:e.name,listeners:[a],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,a){return{Type:"AWS::AppMesh::VirtualNode",Properties:{MeshName:a,VirtualNodeName:e.name,Spec:{Listeners:e.listeners.map((r)=>({PortMapping:{Port:r.port,Protocol:r.protocol},...r.healthCheck&&{HealthCheck:{Protocol:r.healthCheck.protocol,...r.healthCheck.path&&{Path:r.healthCheck.path},IntervalMillis:r.healthCheck.interval*1000,TimeoutMillis:r.healthCheck.timeout*1000,HealthyThreshold:r.healthCheck.healthyThreshold,UnhealthyThreshold:r.healthCheck.unhealthyThreshold}}})),ServiceDiscovery:{AWSCloudMap:{NamespaceName:e.serviceDiscovery.namespace,ServiceName:e.serviceDiscovery.serviceName}}}}}}generateVirtualRouterCF(e,a){return{Type:"AWS::AppMesh::VirtualRouter",Properties:{MeshName:a,VirtualRouterName:e.name,Spec:{Listeners:e.listeners.map((r)=>({PortMapping:{Port:r.port,Protocol:r.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 Rf=new vl;class Tl{layers=new Map;versions=new Map;permissions=new Map;layerCounter=0;versionCounter=0;permissionCounter=0;createLayer(e){let a=`layer-${Date.now()}-${this.layerCounter++}`,r=1,n={id:a,layerArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:1`,version:1,...e};return this.layers.set(a,n),n}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 a=this.layers.get(e);if(!a)throw Error(`Layer not found: ${e}`);let r=`version-${Date.now()}-${this.versionCounter++}`,n=a.version+1,i={id:r,layerName:a.layerName,version:n,createdAt:new Date,compatibleRuntimes:a.compatibleRuntimes,size:a.size,codeHash:this.generateHash()};return this.versions.set(r,i),a.version=n,a.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${a.layerName}:${n}`,i}addPermission(e){let a=`permission-${Date.now()}-${this.permissionCounter++}`,r={id:a,layerName:e.layerName,version:e.version,principal:e.principal,action:"lambda:GetLayerVersion",organizationId:e.organizationId};return this.permissions.set(a,r),r}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((a)=>a.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 Pf=new Tl;class El{versions=new Map;aliases=new Map;deployments=new Map;versionCounter=0;aliasCounter=0;deploymentCounter=0;publishVersion(e){let a=`version-${Date.now()}-${this.versionCounter++}`,r=this.getNextVersionNumber(e.functionName),n={id:a,functionName:e.functionName,version:r.toString(),functionArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${r}`,codeHash:this.generateHash(),description:e.description,runtime:e.runtime,memorySize:e.memorySize,timeout:e.timeout,publishedAt:new Date};return this.versions.set(a,n),n}getNextVersionNumber(e){let a=Array.from(this.versions.values()).filter((r)=>r.functionName===e).map((r)=>parseInt(r.version));return a.length>0?Math.max(...a)+1:1}createAlias(e){let a=`alias-${Date.now()}-${this.aliasCounter++}`,r={id:a,aliasArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${e.aliasName}`,revisionId:this.generateHash(),...e};return this.aliases.set(a,r),r}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,a){let r=this.aliases.get(e);if(!r)throw Error(`Alias not found: ${e}`);return r.functionVersion=a,r.revisionId=this.generateHash(),r}configureWeightedRouting(e,a){let r=this.aliases.get(e);if(!r)throw Error(`Alias not found: ${e}`);return r.routingConfig={additionalVersionWeights:a},r}createCanaryDeployment(e){let a=`deployment-${Date.now()}-${this.deploymentCounter++}`,r=Array.from(this.aliases.values()).find((i)=>i.functionName===e.functionName&&i.aliasName===e.aliasName);if(!r)r=this.createAlias({functionName:e.functionName,aliasName:e.aliasName,functionVersion:e.fromVersion});this.configureWeightedRouting(r.id,{[e.toVersion]:e.canaryWeight});let n={id:a,functionName:e.functionName,fromVersion:e.fromVersion,toVersion:e.toVersion,aliasName:e.aliasName,strategy:"canary",status:"in_progress",startedAt:new Date};return this.deployments.set(a,n),n}completeDeployment(e){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);let r=Array.from(this.aliases.values()).find((n)=>n.functionName===a.functionName&&n.aliasName===a.aliasName);if(r)r.functionVersion=a.toVersion,r.routingConfig=void 0;return a.status="completed",a.completedAt=new Date,a}rollbackDeployment(e){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);let r=Array.from(this.aliases.values()).find((n)=>n.functionName===a.functionName&&n.aliasName===a.aliasName);if(r)r.functionVersion=a.fromVersion,r.routingConfig=void 0;return a.status="failed",a.completedAt=new Date,a}generateHash(){return Math.random().toString(36).substring(2,15)}getVersion(e){return this.versions.get(e)}listVersions(e){let a=Array.from(this.versions.values());return e?a.filter((r)=>r.functionName===e):a}getAlias(e){return this.aliases.get(e)}listAliases(e){let a=Array.from(this.aliases.values());return e?a.filter((r)=>r.functionName===e):a}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(([a,r])=>({FunctionVersion:a,FunctionWeight:r}))}}}}}clear(){this.versions.clear(),this.aliases.clear(),this.deployments.clear(),this.versionCounter=0,this.aliasCounter=0,this.deploymentCounter=0}}var Nf=new El;class Cl{configs=new Map;provisionedConfigs=new Map;schedules=new Map;autoScalingConfigs=new Map;configCounter=0;provisionedCounter=0;scheduleCounter=0;autoScalingCounter=0;setReservedConcurrency(e){let a=`concurrency-${Date.now()}-${this.configCounter++}`,r={id:a,functionName:e.functionName,reservedConcurrency:e.reservedConcurrency};return this.configs.set(a,r),r}setProvisionedConcurrency(e){let a=`provisioned-${Date.now()}-${this.provisionedCounter++}`,r={id:a,functionName:e.functionName,qualifier:e.qualifier,provisionedConcurrentExecutions:e.provisionedConcurrentExecutions,status:"pending",lastModified:new Date};return this.provisionedConfigs.set(a,r),setTimeout(()=>{r.status="ready",r.allocatedConcurrency=e.provisionedConcurrentExecutions,r.availableConcurrency=e.provisionedConcurrentExecutions},100),r}configureWarmPool(e){return this.setProvisionedConcurrency({functionName:e.functionName,qualifier:e.alias,provisionedConcurrentExecutions:e.minInstances})}createSchedule(e){let a=`schedule-${Date.now()}-${this.scheduleCounter++}`,r={id:a,...e};return this.schedules.set(a,r),r}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 a=`autoscaling-${Date.now()}-${this.autoScalingCounter++}`,r={id:a,...e};return this.autoScalingConfigs.set(a,r),r}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 Df=new Cl;class wl{destinations=new Map;records=new Map;eventBridgeDestinations=new Map;destinationCounter=0;recordCounter=0;eventBridgeCounter=0;configureDestinations(e){let a=`destination-${Date.now()}-${this.destinationCounter++}`,r={id:a,...e};return this.destinations.set(a,r),r}configureSQSDestination(e){let a={type:"sqs",arn:e.queueArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?a:void 0,failureDestination:e.onFailure?a:void 0,maxEventAge:21600,maxRetries:2})}configureSNSDestination(e){let a={type:"sns",arn:e.topicArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?a:void 0,failureDestination:e.onFailure?a:void 0,maxEventAge:21600,maxRetries:2})}configureEventBridgeDestination(e){let a={type:"eventbridge",arn:e.eventBusArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?a:void 0,failureDestination:e.onFailure?a:void 0,maxEventAge:21600,maxRetries:2})}configureLambdaDestination(e){let a={type:"lambda",arn:e.destinationFunctionArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?a:void 0,failureDestination:e.onFailure?a: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 a=`eventbridge-${Date.now()}-${this.eventBridgeCounter++}`,r={id:a,functionName:e.functionName,eventBusArn:e.eventBusArn,detailType:e.detailType||"Lambda Function Invocation Result",source:e.source||`lambda.${e.functionName}`};return this.eventBridgeDestinations.set(a,r),r}sendToDestination(e){let a=Array.from(this.destinations.values()).find((o)=>o.functionName===e.functionName);if(!a)return null;let r=e.status==="success"?a.successDestination:a.failureDestination;if(!r)return null;let n=`record-${Date.now()}-${this.recordCounter++}`,i={id:n,timestamp:new Date,functionName:e.functionName,requestId:e.requestId,status:e.status,destinationType:r.type,destinationArn:r.arn,payload:e.payload,error:e.error};return this.records.set(n,i),i}getDestination(e){return this.destinations.get(e)}listDestinations(e){let a=Array.from(this.destinations.values());return e?a.filter((r)=>r.functionName===e):a}getDestinationRecords(e){let a=Array.from(this.records.values());return e?a.filter((r)=>r.functionName===e):a}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 kf=new wl;class Al{vpcConfigs=new Map;endpoints=new Map;networkInterfaces=new Map;connectivity=new Map;configCounter=0;endpointCounter=0;eniCounter=0;connectivityCounter=0;configureVPC(e){let a=`vpc-config-${Date.now()}-${this.configCounter++}`,r={id:a,...e};this.vpcConfigs.set(a,r);for(let n of e.subnetIds)this.createNetworkInterface({functionName:e.functionName,subnetId:n});return r}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 a=`endpoint-${Date.now()}-${this.endpointCounter++}`,r={id:a,...e};return this.endpoints.set(a,r),r}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 a=`eni-${Date.now()}-${this.eniCounter++}`,r={id:a,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(a,r),setTimeout(()=>{r.status="available"},100),r}analyzeConnectivity(e){let a=`connectivity-${Date.now()}-${this.connectivityCounter++}`,r=Array.from(this.vpcConfigs.values()).find((d)=>d.functionName===e.functionName),n=Array.from(this.endpoints.values()).filter((d)=>d.vpcId===r?.vpcId).map((d)=>d.serviceName),i=[],o=e.hasNATGateway??!1,c=e.hasInternetGateway??!1;if(!o&&!c)i.push("Add NAT Gateway for internet access");if(!n.includes("com.amazonaws.us-east-1.s3"))i.push("Add S3 VPC endpoint to reduce NAT costs");if(!n.includes("com.amazonaws.us-east-1.dynamodb"))i.push("Add DynamoDB VPC endpoint for private access");let u={id:a,functionName:e.functionName,hasInternetAccess:o||c,hasNATGateway:o,hasVPCEndpoints:n.length>0,endpoints:n,recommendations:i};return this.connectivity.set(a,u),u}getVPCConfig(e){return this.vpcConfigs.get(e)}listVPCConfigs(e){let a=Array.from(this.vpcConfigs.values());return e?a.filter((r)=>r.functionName===e):a}getNetworkInterfaces(e){return Array.from(this.networkInterfaces.values()).filter((a)=>a.functionName===e)}listVPCEndpoints(e){let a=Array.from(this.endpoints.values());return e?a.filter((r)=>r.vpcId===e):a}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((a)=>({IpProtocol:a.protocol,FromPort:a.fromPort,ToPort:a.toPort,...a.cidrIp&&{CidrIp:a.cidrIp},...a.sourceSecurityGroupId&&{SourceSecurityGroupId:a.sourceSecurityGroupId}}))},...e.egressRules&&{SecurityGroupEgress:e.egressRules.map((a)=>({IpProtocol:a.protocol,FromPort:a.fromPort,ToPort:a.toPort,CidrIp:a.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 _f=new Al;class Il{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(e){let a=`dlq-${Date.now()}-${this.configCounter++}`,r={id:a,...e};return this.dlqConfigs.set(a,r),r}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 a=this.configureSQSDLQ({functionName:e.functionName,queueArn:e.queueArn});return this.createDLQAlarm({dlqConfigId:a.id,alarmName:`${e.functionName}-dlq-alarm`,threshold:e.alarmThreshold,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0}),a}sendToDLQ(e){let a=`message-${Date.now()}-${this.messageCounter++}`,r={id:a,timestamp:new Date,...e};return this.messages.set(a,r),r}createDLQAlarm(e){let a=`alarm-${Date.now()}-${this.alarmCounter++}`,r={id:a,...e};return this.alarms.set(a,r),r}createAgeAlarm(e){let a=this.dlqConfigs.get(e.dlqConfigId);if(!a)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:e.dlqConfigId,alarmName:`${a.functionName}-dlq-age-alarm`,threshold:e.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0})}async reprocessMessage(e){let a=this.messages.get(e);if(!a)throw Error(`Message not found: ${e}`);let r=Array.from(this.dlqConfigs.values()).find((o)=>o.functionName===a.functionName);if(!r)throw Error(`DLQ config not found for function: ${a.functionName}`);let n=`reprocess-${Date.now()}-${this.reprocessCounter++}`,i={id:n,dlqConfigId:r.id,messageId:e,status:"pending",startedAt:new Date};return this.reprocessing.set(n,i),setTimeout(()=>{i.status="processing",setTimeout(()=>{let o=Math.random()>0.3;if(i.status=o?"success":"failed",i.completedAt=new Date,!o)i.error="Reprocessing failed - same error occurred";else this.messages.delete(e)},100)},50),i}async batchReprocess(e){let a=this.dlqConfigs.get(e.dlqConfigId);if(!a)throw Error(`DLQ config not found: ${e.dlqConfigId}`);let r=Array.from(this.messages.values()).filter((n)=>n.functionName===a.functionName).slice(0,e.maxMessages||10).map((n)=>this.reprocessMessage(n.id));return Promise.all(r)}getDLQStats(e){let a=this.dlqConfigs.get(e);if(!a)throw Error(`DLQ config not found: ${e}`);let r=Array.from(this.messages.values()).filter((c)=>c.functionName===a.functionName),n={},i=0;for(let c of r)n[c.errorType]=(n[c.errorType]||0)+1,i+=c.attemptCount;let o=r.map((c)=>c.timestamp);return{totalMessages:r.length,oldestMessage:o.length>0?new Date(Math.min(...o.map((c)=>c.getTime()))):void 0,newestMessage:o.length>0?new Date(Math.max(...o.map((c)=>c.getTime()))):void 0,averageAttempts:r.length>0?i/r.length:0,errorTypes:n}}getDLQConfig(e){return this.dlqConfigs.get(e)}listDLQConfigs(){return Array.from(this.dlqConfigs.values())}getDLQMessages(e){let a=this.dlqConfigs.get(e);if(!a)return[];return Array.from(this.messages.values()).filter((r)=>r.functionName===a.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 a=this.dlqConfigs.get(e.dlqConfigId);if(!a)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`DLQ alarm for ${a.functionName}`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:e.evaluationPeriods,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:a.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 xf=new Il;class Rl{policies=new Map;healthChecks=new Map;trafficPolicies=new Map;policyCounter=0;healthCheckCounter=0;trafficPolicyCounter=0;createWeightedPolicy(e){let a=`policy-${Date.now()}-${this.policyCounter++}`,r={id:a,type:"weighted",...e};return this.policies.set(a,r),r}createLatencyPolicy(e){let a=`policy-${Date.now()}-${this.policyCounter++}`,r={id:a,type:"latency",...e};return this.policies.set(a,r),r}createFailoverPolicy(e){let a=`policy-${Date.now()}-${this.policyCounter++}`,r={id:a,type:"failover",...e};return this.policies.set(a,r),r}createGeolocationPolicy(e){let a=`policy-${Date.now()}-${this.policyCounter++}`,r={id:a,type:"geolocation",...e};return this.policies.set(a,r),r}createGeoproximityPolicy(e){let a=`policy-${Date.now()}-${this.policyCounter++}`,r={id:a,type:"geoproximity",...e};return this.policies.set(a,r),r}createHTTPHealthCheck(e){let a=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:a,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(a,r),setTimeout(()=>{r.healthCheckStatus=Math.random()>0.2?"Healthy":"Unhealthy"},100),r}createTCPHealthCheck(e){let a=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:a,type:"tcp",fullyQualifiedDomainName:e.ipAddress,requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(a,r),setTimeout(()=>{r.healthCheckStatus=Math.random()>0.1?"Healthy":"Unhealthy"},100),r}createCalculatedHealthCheck(e){let a=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:a,type:"calculated",requestInterval:30,failureThreshold:0,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(a,r),setTimeout(()=>{let n=e.childHealthChecks.filter((i)=>this.healthChecks.get(i)?.healthCheckStatus==="Healthy").length;r.healthCheckStatus=n>=e.healthThreshold?"Healthy":"Unhealthy"},150),r}createTrafficPolicy(e){let a=`traffic-policy-${Date.now()}-${this.trafficPolicyCounter++}`,r={id:a,version:1,...e};return this.trafficPolicies.set(a,r),r}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 a={},r=[];return e.locations.forEach((n,i)=>{let o=`endpoint${i}`;a[o]={type:"value",value:n.endpoint},r.push({endpointReference:o,region:n.region,latitude:n.latitude,longitude:n.longitude,bias:n.bias})}),this.createTrafficPolicy({name:e.name,document:{recordType:"A",startRule:"geoproximity",endpoints:a,rules:{geoproximity:{ruleType:"geoproximity",locations:r}}}})}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 a={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 r=e;a.Properties.HealthCheckConfig.ChildHealthChecks=r.childHealthChecks,a.Properties.HealthCheckConfig.HealthThreshold=r.healthThreshold}else{if(e.ipAddress)a.Properties.HealthCheckConfig.IPAddress=e.ipAddress;if(e.fullyQualifiedDomainName)a.Properties.HealthCheckConfig.FullyQualifiedDomainName=e.fullyQualifiedDomainName;if(e.port)a.Properties.HealthCheckConfig.Port=e.port;if(e.resourcePath)a.Properties.HealthCheckConfig.ResourcePath=e.resourcePath;if(e.enableSNI)a.Properties.HealthCheckConfig.EnableSNI=!0}return a}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 $f=new Rl;class Pl{configs=new Map;ksks=new Map;validations=new Map;configCounter=0;kskCounter=0;validationCounter=0;enableDNSSEC(e){let a=`dnssec-${Date.now()}-${this.configCounter++}`,r={id:a,hostedZoneId:e.hostedZoneId,status:"SIGNING",signingStatus:"Initializing DNSSEC signing"};if(this.configs.set(a,r),e.kmsKeyArn)this.createKSK({name:`ksk-${e.hostedZoneId}`,hostedZoneId:e.hostedZoneId,kmsKeyArn:e.kmsKeyArn});return setTimeout(()=>{r.status="SIGNED",r.signingStatus="DNSSEC signing complete"},100),r}disableDNSSEC(e){let a=this.configs.get(e);if(!a)throw Error(`DNSSEC config not found: ${e}`);return a.status="DELETING",a.signingStatus="Removing DNSSEC signing",setTimeout(()=>{a.status="NOT_SIGNING",a.signingStatus="DNSSEC signing removed"},100),a}createKSK(e){let a=`ksk-${Date.now()}-${this.kskCounter++}`,r={id:a,status:"ACTIVE",flag:257,keyManagementServiceArn:e.kmsKeyArn,digestAlgorithm:2,keyTag:Math.floor(Math.random()*65535),publicKey:this.generatePublicKey(),...e};r.dnskeyRecord=`${r.flag} 3 8 ${r.publicKey}`;let n=this.generateDigest(r.dnskeyRecord);return r.digestValue=n,r.dsRecord=`${r.keyTag} 8 ${r.digestAlgorithm} ${n}`,this.ksks.set(a,r),r}deactivateKSK(e){let a=this.ksks.get(e);if(!a)throw Error(`KSK not found: ${e}`);return a.status="INACTIVE",a}validateDNSSEC(e){let a=`validation-${Date.now()}-${this.validationCounter++}`,r=e.checkDNSKEY!==!1?Math.random()>0.1:!1,n=e.checkRRSIG!==!1?Math.random()>0.1:!1,i=r&&n,o=[];if(!r)o.push("DNSKEY record not found");if(!n)o.push("RRSIG record not found");let c;if(!r&&!n)c="INSECURE";else if(r&&n&&i)c="VALID";else if(r||n)c="BOGUS",o.push("Invalid signature or incomplete DNSSEC chain");else c="INVALID";let u={id:a,domain:e.domain,validationStatus:c,dnskeyPresent:r,rrsigPresent:n,validSignature:i,errors:o};return this.validations.set(a,u),u}getDNSSECConfig(e){return this.configs.get(e)}listDNSSECConfigs(){return Array.from(this.configs.values())}getKSK(e){return this.ksks.get(e)}listKSKs(e){let a=Array.from(this.ksks.values());return e?a.filter((r)=>r.hostedZoneId===e):a}getDSRecord(e){let a=this.ksks.get(e);if(!a||!a.dsRecord)throw Error("DS record not available");return a.dsRecord}generatePublicKey(){let e="";for(let a=0;a<256;a++)e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return e}generateDigest(e){let a="";for(let r=0;r<64;r++)a+="0123456789ABCDEF".charAt(Math.floor(Math.random()*16));return a}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 Of=new Pl;class Nl{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 a=`endpoint-${Date.now()}-${this.endpointCounter++}`,r={id:a,status:"CREATING",...e};return this.endpoints.set(a,r),setTimeout(()=>{r.status="OPERATIONAL",r.ipAddresses.forEach((n)=>{if(!n.ip)n.ip=`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`})},100),r}createInboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"INBOUND",ipAddresses:e.subnetIds.map((a)=>({subnetId:a})),securityGroupIds:e.securityGroupIds})}createOutboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"OUTBOUND",ipAddresses:e.subnetIds.map((a)=>({subnetId:a})),securityGroupIds:e.securityGroupIds})}createResolverRule(e){let a=`rule-${Date.now()}-${this.ruleCounter++}`,r={id:a,status:"CREATING",...e};return this.rules.set(a,r),setTimeout(()=>{r.status="COMPLETE"},100),r}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 a=`domain-list-${Date.now()}-${this.domainListCounter++}`,r={id:a,status:"CREATING",...e};return this.domainLists.set(a,r),setTimeout(()=>{r.status="COMPLETE"},100),r}createFirewallRuleGroup(e){let a=`rule-group-${Date.now()}-${this.ruleGroupCounter++}`,r={id:a,name:e.name,rules:e.rules.map((n,i)=>({id:`rule-${a}-${i}`,...n})),shareStatus:"NOT_SHARED"};return this.ruleGroups.set(a,r),r}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 a=`firewall-${Date.now()}-${this.firewallCounter++}`,r={id:a,name:e.name,firewallRuleGroupAssociations:e.ruleGroupAssociations.map((n,i)=>({id:`assoc-${a}-${i}`,vpcId:e.vpcId,firewallRuleGroupId:n.firewallRuleGroupId,priority:n.priority,mutationProtection:n.mutationProtection||"DISABLED",status:"COMPLETE"}))};return this.firewalls.set(a,r),r}createMalwareProtectionFirewall(e){let a=this.createFirewallDomainList({name:`${e.name}-malware-domains`,domains:e.maliciousDomains}),r=this.createBlockRule({name:`${e.name}-block-malware`,priority:100,domainListId:a.id,blockResponse:"NXDOMAIN"});return this.createDNSFirewall({name:e.name,vpcId:e.vpcId,ruleGroupAssociations:[{firewallRuleGroupId:r.id,priority:100,mutationProtection:"ENABLED"}]})}getEndpoint(e){return this.endpoints.get(e)}listEndpoints(e){let a=Array.from(this.endpoints.values());return e?a.filter((r)=>r.direction===e):a}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((a)=>({SubnetId:a.subnetId,...a.ip&&{Ip:a.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((a)=>({Ip:a.ip,Port:a.port||53}))},...e.resolverEndpointId&&{ResolverEndpointId:e.resolverEndpointId}}}}generateFirewallRuleGroupCF(e){return{Type:"AWS::Route53Resolver::FirewallRuleGroup",Properties:{Name:e.name,FirewallRules:e.rules.map((a)=>({Name:a.name,Priority:a.priority,Action:a.action,FirewallDomainListId:a.firewallDomainListId,...a.blockResponse&&{BlockResponse:a.blockResponse},...a.blockOverrideDomain&&{BlockOverrideDomain:a.blockOverrideDomain},...a.blockOverrideTTL&&{BlockOverrideTtl:a.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 Lf=new Nl;class Dl{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 a=`bounce-${Date.now()}-${this.bounceCounter++}`,r={id:a,...e};if(this.bounces.set(a,r),e.bounceType==="Permanent")this.addToSuppressionList({emailAddress:e.recipient,reason:"BOUNCE"});return r}recordComplaint(e){let a=`complaint-${Date.now()}-${this.complaintCounter++}`,r={id:a,...e};this.complaints.set(a,r);for(let n of e.recipients)this.addToSuppressionList({emailAddress:n,reason:"COMPLAINT"});return r}createBounceHandler(e){let a=`handler-${Date.now()}-${this.handlerCounter++}`,r={id:a,...e};return this.handlers.set(a,r),r}createAutomaticBounceHandler(e){return this.createBounceHandler({name:e.name,bounceThreshold:5,complaintThreshold:0.1,suppressionDuration:2592000,autoSuppress:!0,notificationTopicArn:e.notificationTopicArn})}addToSuppressionList(e){let a=`suppression-${Date.now()}-${this.suppressionCounter++}`,r=e.expirationDays?new Date(Date.now()+e.expirationDays*24*60*60*1000):void 0,n={id:a,emailAddress:e.emailAddress,reason:e.reason,suppressedAt:new Date,expiresAt:r,bounceCount:e.reason==="BOUNCE"?1:0,complaintCount:e.reason==="COMPLAINT"?1:0};return this.suppressionList.set(e.emailAddress,n),n}removeFromSuppressionList(e){return this.suppressionList.delete(e)}isSuppressed(e){let a=this.suppressionList.get(e);if(!a)return!1;if(a.expiresAt&&a.expiresAt<new Date)return this.suppressionList.delete(e),!1;return!0}getBounceStatistics(e,a){let r=Array.from(this.bounces.values()).filter((p)=>p.timestamp>=e&&p.timestamp<=a),n=r.length,i=r.filter((p)=>p.bounceType==="Permanent").length,o=r.filter((p)=>p.bounceType==="Transient").length,c=n*10,u=n/c*100,d=new Map;for(let p of r)d.set(p.recipient,(d.get(p.recipient)||0)+1);let m=Array.from(d.entries()).map(([p,g])=>({email:p,count:g})).sort((p,g)=>g.count-p.count).slice(0,10);return{totalBounces:n,permanentBounces:i,transientBounces:o,bounceRate:u,topRecipients:m}}getComplaintStatistics(e,a){let r=Array.from(this.complaints.values()).filter((d)=>d.timestamp>=e&&d.timestamp<=a),n=r.length,i=new Set;for(let d of r)for(let m of d.recipients)i.add(m);let o=i.size,c=n*1000,u=n/c*100;return{totalComplaints:n,uniqueComplainters:o,complaintRate:u}}calculateReputationMetrics(){let e=`metrics-${Date.now()}-${this.metricsCounter++}`,a=new Date,r=new Date(a.getTime()-86400000),n=this.getBounceStatistics(r,a),i=this.getComplaintStatistics(r,a),o;if(n.bounceRate>10||i.complaintRate>0.5)o="Shutdown";else if(n.bounceRate>5||i.complaintRate>0.1)o="Probation";else if(n.bounceRate>2||i.complaintRate>0.05)o="Warning";else o="Good";let c={id:e,timestamp:a,bounceRate:n.bounceRate,complaintRate:i.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:n.totalBounces*10,reputationStatus:o};return this.metrics.set(e,c),c}getBounces(e){let a=Array.from(this.bounces.values());return e?a.filter((r)=>r.messageId===e):a}getComplaints(e){let a=Array.from(this.complaints.values());return e?a.filter((r)=>r.messageId===e):a}listSuppressionList(e){let a=Array.from(this.suppressionList.values());return e?a.filter((r)=>r.reason===e):a}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 Mf=new Dl;class kl{events=new Map;campaigns=new Map;reports=new Map;abTests=new Map;eventCounter=0;campaignCounter=0;reportCounter=0;abTestCounter=0;trackEvent(e){let a=`event-${Date.now()}-${this.eventCounter++}`,r={id:a,...e};if(this.events.set(a,r),e.tags?.campaignId)this.updateCampaignStats(e.tags.campaignId,e.eventType);return r}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 a=`campaign-${Date.now()}-${this.campaignCounter++}`,r={id:a,sentCount:0,deliveredCount:0,openCount:0,clickCount:0,bounceCount:0,complaintCount:0,createdAt:new Date,...e};return this.campaigns.set(a,r),r}updateCampaignStats(e,a){let r=this.campaigns.get(e);if(!r)return;switch(a){case"send":r.sentCount++;break;case"delivery":r.deliveredCount++;break;case"open":r.openCount++;break;case"click":r.clickCount++;break;case"bounce":r.bounceCount++;break;case"complaint":r.complaintCount++;break}}generateReport(e){let a=`report-${Date.now()}-${this.reportCounter++}`,r=Array.from(this.events.values()).filter((C)=>{let N=C.timestamp>=e.startDate&&C.timestamp<=e.endDate,R=!e.campaignId||C.tags?.campaignId===e.campaignId;return N&&R}),n=r.filter((C)=>C.eventType==="send").length,i=r.filter((C)=>C.eventType==="delivery").length,o=r.filter((C)=>C.eventType==="open").length,c=r.filter((C)=>C.eventType==="click").length,u=r.filter((C)=>C.eventType==="bounce").length,d=r.filter((C)=>C.eventType==="complaint").length,m=n>0?i/n*100:0,p=i>0?o/i*100:0,g=i>0?c/i*100:0,h=o>0?c/o*100:0,y=n>0?u/n*100:0,f=i>0?d/i*100:0,b=new Map;for(let C of r)if(C.eventType==="click"){let N=C;b.set(N.link,(b.get(N.link)||0)+1)}let v=Array.from(b.entries()).map(([C,N])=>({link:C,clicks:N})).sort((C,N)=>N.clicks-C.clicks).slice(0,10),T={desktop:0,mobile:0,tablet:0,unknown:0};for(let C of r)if(C.eventType==="open"||C.eventType==="click"){let N=C.userAgent.toLowerCase();if(N.includes("mobile"))T.mobile++;else if(N.includes("tablet"))T.tablet++;else if(N.includes("mozilla"))T.desktop++;else T.unknown++}let I={id:a,campaignId:e.campaignId,startDate:e.startDate,endDate:e.endDate,totalSent:n,totalDelivered:i,totalOpened:o,totalClicked:c,totalBounced:u,totalComplaints:d,deliveryRate:m,openRate:p,clickRate:g,clickToOpenRate:h,bounceRate:y,complaintRate:f,topLinks:v,deviceBreakdown:T,locationBreakdown:{}};return this.reports.set(a,I),I}createABTest(e){let a=`abtest-${Date.now()}-${this.abTestCounter++}`,r={id:a,name:e.name,variants:e.variants.map((n,i)=>({id:`variant-${a}-${i}`,sentCount:0,openCount:0,clickCount:0,conversionCount:0,...n})),status:"draft"};return this.abTests.set(a,r),r}startABTest(e){let a=this.abTests.get(e);if(!a)throw Error(`A/B test not found: ${e}`);return a.status="running",a.startedAt=new Date,a}completeABTest(e){let a=this.abTests.get(e);if(!a)throw Error(`A/B test not found: ${e}`);let r=a.variants[0],n=0;for(let i of a.variants){let o=i.sentCount>0?i.openCount/i.sentCount:0;if(o>n)n=o,r=i}return a.status="completed",a.completedAt=new Date,a.winner=r.id,a}getCampaign(e){return this.campaigns.get(e)}listCampaigns(){return Array.from(this.campaigns.values())}getEvents(e){let a=Array.from(this.events.values());if(e?.messageId)a=a.filter((r)=>r.messageId===e.messageId);if(e?.eventType)a=a.filter((r)=>r.eventType===e.eventType);if(e?.startDate)a=a.filter((r)=>r.timestamp>=e.startDate);if(e?.endDate)a=a.filter((r)=>r.timestamp<=e.endDate);return a}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 Uf=new kl;class _l{dashboards=new Map;warmupPlans=new Map;domainReputations=new Map;dashboardCounter=0;warmupCounter=0;domainCounter=0;getReputationDashboard(){let e=`dashboard-${Date.now()}-${this.dashboardCounter++}`,a=Math.random()*5,r=Math.random()*0.5,n=Math.floor(Math.random()*10),i=Math.max(0,100-a*10-r*100-n*2),o=[];if(a>2)o.push("Reduce bounce rate by cleaning email list");if(r>0.1)o.push("Review email content and unsubscribe process");if(n>5)o.push("Improve email relevance and targeting");let c={id:e,timestamp:new Date,overallScore:i,bounceRate:a,complaintRate:r,spamReports:n,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:o};return this.dashboards.set(e,c),c}checkBlacklists(){return["Spamhaus ZEN","Spamcop","SORBS","Barracuda","URIBL"].map((e)=>({listName:e,listed:Math.random()>0.95,delistUrl:`https://www.${e.toLowerCase().replace(/\s/g,"")}.org/delist`}))}createWarmupPlan(e){let a=`warmup-${Date.now()}-${this.warmupCounter++}`,r=[],n=(e.targetDailyLimit-e.initialDailyLimit)/e.durationDays;for(let o=0;o<e.durationDays;o++)r.push(Math.floor(e.initialDailyLimit+n*o));let i={id:a,name:e.name,startDate:new Date,currentDay:1,totalDays:e.durationDays,dailyLimits:r,currentLimit:r[0],status:"active"};return this.warmupPlans.set(a,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 a=this.warmupPlans.get(e);if(!a)throw Error(`Warmup plan not found: ${e}`);if(a.currentDay<a.totalDays)a.currentDay++,a.currentLimit=a.dailyLimits[a.currentDay-1];if(a.currentDay>=a.totalDays)a.status="completed";return a}trackDomainReputation(e){let a=`domain-${Date.now()}-${this.domainCounter++}`,r=e.delivered/e.totalSent*100,n=e.delivered>0?e.opened/e.delivered*100:0,i=e.delivered>0?e.clicked/e.delivered*100:0,o=e.bounced/e.totalSent*100,c=e.delivered>0?e.complained/e.delivered*100:0,u=n*0.4+i*0.6,d=Math.max(0,100-o*10-c*100+u*0.2),m={id:a,domain:e.domain,reputationScore:d,totalSent:e.totalSent,deliveryRate:r,openRate:n,clickRate:i,bounceRate:o,complaintRate:c,engagementScore:u};return this.domainReputations.set(e.domain,m),m}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 Bf=new _l;class xl{templates=new Map;versions=new Map;tests=new Map;templateCounter=0;testCounter=0;createTemplate(e){let a=`template-${Date.now()}-${this.templateCounter++}`,r=this.extractVariables(e.subject+e.htmlPart+e.textPart),n={id:a,variables:r,createdAt:new Date,updatedAt:new Date,version:1,...e};return this.templates.set(a,n),this.addVersion({templateId:a,version:1,subject:e.subject,htmlPart:e.htmlPart,textPart:e.textPart,createdBy:"system"}),n}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>
|
|
@@ -7283,7 +7283,7 @@ export const queue = __handlers.queue
|
|
|
7283
7283
|
export const cli = __handlers.cli
|
|
7284
7284
|
`}var ns=["adapter.ts","recursion.ts","auto-recursion.ts"];function is(){return be(es(rs(import.meta.url)),"runtime")}function Tu(e,a,r){for(let n of e??[])r?.(`build: ${n}`),Hi(n,{stdio:"inherit",cwd:a})}function Uo(e){return zi("sha256").update(e).digest("hex")}function fa(e,a,r){return`deployments/${e}/${a}/${r}.zip`}async function un(e){let a=as(e.projectRoot??process.cwd()),{app:r}=e;if(!e.skipBuild)Tu(r.build,a,e.onStep);let n=r.entry;if(!n)throw Error("serverless app: `entry` is required to package a Node/Bun application");let i=ts(n)?n:be(a,n),o=Ji(be(Xi(),"tscloud-pkg-"));try{for(let h of ns)Qi(be(is(),h),be(o,h));let c=be(o,"bootstrap.ts");Zi(c,vu({entryImport:i,adapterImport:"./adapter"})),e.onStep?.("bundling application");let u=await Bun.build({entrypoints:[c],target:r.kind==="bun"?"bun":"node",format:"esm",minify:!1,sourcemap:"none"});if(!u.success){let h=u.logs.map((y)=>String(y)).join(`
|
|
7285
7285
|
`);throw Error(`serverless app bundle failed:
|
|
7286
|
-
${h}`)}let d=u.outputs[0],m=Buffer.from(await d.arrayBuffer()),p="index",g=Ai([{name:`${p}.mjs`,data:m}]);return{zip:g,bundle:m,sha256:Uo(g),handlerFile:p,handlers:{http:r.handlers?.http??`${p}.http`,queue:r.handlers?.queue??`${p}.queue`,cli:r.handlers?.cli??`${p}.cli`},bundleBytes:m.length}}finally{Yi(o,{recursive:!0,force:!0})}}var Eu=["18","20","22"];function ss(e){if(!e)return"22";let a=String(e).match(/(\d+)/);return a?a[1]:"22"}function Bo(e){let a=e.kind??"node";if(a==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(a==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let r=ss(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&Eu.includes(r))return{lambdaRuntime:e.runtime&&e.runtime.startsWith("nodejs")?e.runtime:`nodejs${r}.x`,kind:"node",version:r,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:r,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function Wt(e,a,r){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${a}-${r}-default`}];return e.queues.map((n)=>{if(typeof n==="string")return{name:`${a}-${r}-${n}`};let[i,o]=Object.entries(n)[0];return{name:`${a}-${r}-${i}`,concurrency:o}})}function ha(e,a,r){return Wt(e,a,r).map((n)=>n.name)}function ya(e){let{app:a,environment:r,handlers:n}=e,i=e.config.project.slug,o=Bo(a).lambdaRuntime,c=a.architecture??"x86_64",u=e.config.project.region,d={http:`${i}-${r}-http`,queue:`${i}-${r}-queue`,cli:`${i}-${r}-cli`};if(a.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 m=Wt(a,i,r),p=m.map((O)=>O.name),g=p.length>0,h=a.logRetention??14,y=a.packaging==="image";if(y&&a.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 f=(a.scheduler??"on")!=="off",b=(a.cache?.driver??"dynamodb")==="dynamodb",T=Boolean(a.assets),w=Ro(i,r),I=a.tmpStorage??512,v={},N={},R=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:t.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:t.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${i}-${r}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${i}/${r}/*`),t.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${i}/${r}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[t.sub(`arn:aws:s3:::${w}`),t.sub(`arn:aws:s3:::${w}/*`),...a.storage?.bucket?[t.sub(`arn:aws:s3:::${a.storage.bucket}`),t.sub(`arn:aws:s3:::${a.storage.bucket}/*`)]:[]]}]}}];if(g)R[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:t.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${i}-${r}-*`)});if(b)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:t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${i}-${r}-cache*`)});let k=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(a.vpc?.subnets?.length)k.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(a.lambdaInsights)k.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");v.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${i}-${r}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:k,Policies:R}};let x=(O)=>({TSCLOUD_LAMBDA_MODE:O,TSCLOUD_ENV:r,...a.octane?{TSCLOUD_OCTANE:"1"}:{},...a.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...b?{TSCLOUD_CACHE_TABLE:`${i}-${r}-cache`}:{},...g?{TSCLOUD_QUEUE:p[0]}:{},...a.env??{}}),M=Boolean(a.efs),B=typeof a.efs==="object"?a.efs:{},_=B.mountPath??"/mnt/local",U=M&&!B.accessPointArn,Y=B.accessPointArn??(U?t.getAtt("EfsAccessPoint","Arn"):void 0),q=a.vpc?.subnets??[],Q=q.length>0,V=a.cache?.driver==="elasticache"||a.database?.connection==="aurora-serverless"||Boolean(a.rdsProxy)||M;if(V&&!Q)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let me=Q?{VpcConfig:{SubnetIds:q,SecurityGroupIds:[...a.vpc?.securityGroups??[],...V?[t.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},Me=U?q.map((O,G)=>`EfsMountTarget${G}`):[],vt=M?{FileSystemConfigs:[{Arn:Y,LocalMountPath:_}]}:{};if(M)R[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function Z(O,G,W,K,ne,Ze,ce,Xe=I){v[`${O}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${G}`,RetentionInDays:h}};let Tt=[...e.runtimeLayers??[],...a.lambdaInsights?[a.lambdaInsights.layerArn]:[]],Pt=y?{PackageType:"Image",Code:{ImageUri:t.ref("ImageUri")},...a.kind==="php"?{}:{ImageConfig:{Command:[W]}}}:{Runtime:o,Handler:W,Code:{S3Bucket:t.ref("ArtifactBucket"),S3Key:t.ref("ArtifactKey")},...Tt.length?{Layers:[...new Set(Tt)]}:{}};v[O]={Type:"AWS::Lambda::Function",DependsOn:[`${O}LogGroup`,...Me],Properties:{FunctionName:G,Architectures:[c],MemorySize:ne,Timeout:Ze,Role:t.getAtt("AppRole","Arn"),Environment:{Variables:x(K)},EphemeralStorage:{Size:Xe},...Pt,...ce!==void 0?{ReservedConcurrentExecutions:ce}:{},...me,...vt}}}if(Z("HttpFunction",d.http,n.http,"http",a.memory??1024,a.timeout??28,a.concurrency,I),Z("CliFunction",d.cli,n.cli,"cli",a.cliMemory??1024,a.cliTimeout??900,void 0,a.cliTmpStorage??I),g)Z("QueueFunction",d.queue,n.queue,"queue",a.queueMemory??1024,a.queueTimeout??120,void 0,a.queueTmpStorage??I);let J=(a.provisionedConcurrency??0)>0?a.provisionedConcurrency:0,ee=["HttpFunction","CliFunction",...g?["QueueFunction"]:[]];if(J)for(let O of ee)v[`${O}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:t.ref(O)}},v[`${O}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:t.ref(O),Name:"live",FunctionVersion:t.getAtt(`${O}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:J}}};let pe=(O)=>J?t.ref(`${O}Alias`):t.getAtt(O,"Arn"),te=(O)=>J?t.ref(`${O}Alias`):t.ref(O);v.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${i}-${r}`,ProtocolType:"HTTP"}},v.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:t.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:pe("HttpFunction"),PayloadFormatVersion:"2.0"}},v.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:t.ref("HttpApi"),RouteKey:"$default",Target:t.join("/",["integrations",t.ref("HttpIntegration")])}},v.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},v.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:te("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},N.HttpApiEndpoint={Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint")},N.HttpApiId={Description:"HTTP API id",Value:t.ref("HttpApi")};let oe=(Array.isArray(a.domain)?a.domain:a.domain?[a.domain]:[]).filter(Boolean);if(oe.length){if(!a.certificateArn&&!a.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let O=a.certificateArn;if(!O)v.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:oe[0],...oe.length>1?{SubjectAlternativeNames:oe.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:oe.map((G)=>({DomainName:G,HostedZoneId:a.hostedZoneId}))}},O=t.ref("HttpCertificate");oe.forEach((G,W)=>{let K=`HttpDomain${W}`;if(v[K]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:G,DomainNameConfigurations:[{CertificateArn:O,EndpointType:"REGIONAL"}]}},v[`HttpApiMapping${W}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:t.ref("HttpApi"),DomainName:t.ref(K),Stage:"$default"}},a.hostedZoneId)v[`HttpDomainRecord${W}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a.hostedZoneId,Name:G,Type:"A",AliasTarget:{DNSName:t.getAtt(K,"RegionalDomainName"),HostedZoneId:t.getAtt(K,"RegionalHostedZoneId")}}};N[`CustomDomain${W}`]={Description:`Custom domain ${G}`,Value:G},N[`CustomDomainTarget${W}`]={Description:`Point ${G} (CNAME/alias) at this APIGW regional domain`,Value:t.getAtt(K,"RegionalDomainName")}})}if(g)v.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${i}-${r}-dlq`,MessageRetentionPeriod:1209600}},m.forEach((O,G)=>{let W=`AppQueue${G}`,K=a.queueTimeout??120;v[W]={Type:"AWS::SQS::Queue",Properties:{QueueName:O.name,VisibilityTimeout:Math.min(43200,K*6),RedrivePolicy:{deadLetterTargetArn:t.getAtt("AppQueueDlq","Arn"),maxReceiveCount:a.queueTries??3}}};let ne=O.concurrency??a.queueConcurrency;v[`${W}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:t.getAtt(W,"Arn"),FunctionName:te("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...ne?{ScalingConfig:{MaximumConcurrency:Math.max(2,ne)}}:{}}},N[`QueueUrl${G}`]={Description:`Queue URL: ${O.name}`,Value:t.ref(W)}});if(f)v.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${r}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:pe("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},v.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:te("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.getAtt("SchedulerRule","Arn")}};if(a.warm&&a.warm>0){let O={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},G=(a.warmFunctions??["http"]).filter((W)=>W!=="queue"||g);for(let W of G){let K=W.charAt(0).toUpperCase()+W.slice(1),ne=Math.ceil(a.warm/5),Ze=0;for(let ce=0;ce<ne;ce++){let Xe=Math.min(5,a.warm-Ze);v[`Warmer${K}Rule${ce}`]={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${r}-warmer-${W}-${ce}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Xe},(Tt,Pt)=>({Id:`warm-${W}-${ce}-${Pt}`,Arn:t.getAtt(O[W],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Ze+=Xe}v[`Warmer${K}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:t.ref(O[W]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${i}-${r}-warmer-${W}-*`)}}}}if(b)v.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${i}-${r}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},N.CacheTableName={Description:"DynamoDB cache table",Value:t.ref("CacheTable")};if(T){if(v.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:w,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},v.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${i}-${r}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},v.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:t.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:t.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...a.assetDomain?{Aliases:[a.assetDomain],ViewerCertificate:{AcmCertificateArn:a.assetCertificateArn??t.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},a.assetDomain){if(!a.assetCertificateArn){if(!a.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(u!=="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 ${u}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);v.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:a.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:a.assetDomain,HostedZoneId:a.hostedZoneId}]}}}if(a.hostedZoneId)v.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a.hostedZoneId,Name:a.assetDomain,Type:"A",AliasTarget:{DNSName:t.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};N.AssetDomain={Description:"Custom asset CDN host",Value:a.assetDomain}}v.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:t.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:t.sub(`arn:aws:s3:::${w}/*`),Condition:{StringEquals:{"AWS:SourceArn":t.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},N.AssetsBucketName={Description:"Assets bucket",Value:t.ref("AssetsBucket")},N.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:t.getAtt("AssetsDistribution","DomainName")}}if(a.firewall?.enabled){let O=[],G=0;if(a.firewall.rateLimit)O.push({Name:"rate-limit",Priority:G++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:a.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${r}-rate`}});let W={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let K of a.firewall.rules??[]){let ne=W[K];if(!ne)continue;O.push({Name:`managed-${K}`,Priority:G++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:ne}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${r}-${K}`}})}v.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${i}-${r}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:O,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${r}-waf`}}},N.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:t.getAtt("WebAcl","Arn")}}if(Q&&V){if(!a.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.");v.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:a.vpc.id,GroupDescription:`${i}-${r} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(U)v.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${i}-${r}-efs`}]}},q.forEach((O,G)=>{v[`EfsMountTarget${G}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:t.ref("EfsFileSystem"),SubnetId:O,SecurityGroups:[t.getAtt("DataSecurityGroup","GroupId")]}}}),v.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:t.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},N.EfsFileSystemId={Description:"EFS file system id",Value:t.ref("EfsFileSystem")};if(a.cache?.driver==="elasticache")v.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${i}-${r} cache subnets`,SubnetIds:q}},v.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${i}-${r}-cache`,ReplicationGroupDescription:`${i}-${r} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},N.CacheEndpoint={Description:"Redis primary endpoint",Value:t.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(a.database?.connection==="aurora-serverless")v.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${i}-${r} db subnets`,SubnetIds:q}},v.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${i}/${r}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},v.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${i}-${r}-db`,DatabaseName:"app",MasterUsername:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:a.database?.minCapacity??0.5,MaxCapacity:a.database?.maxCapacity??4},DBSubnetGroupName:t.ref("DbSubnetGroup"),VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")]}},v.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:t.ref("DbCluster")}},N.DbEndpoint={Description:"Aurora cluster endpoint",Value:t.getAtt("DbCluster","Endpoint.Address")};if(a.rdsProxy&&a.database?.connection==="aurora-serverless")v.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:t.ref("DbSecret")}]}}]}},v.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof a.rdsProxy==="object"&&a.rdsProxy.name?a.rdsProxy.name:`${i}-${r}-proxy`,EngineFamily:"MYSQL",RoleArn:t.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:t.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:q,VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},v.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:t.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[t.ref("DbCluster")]}},N.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:t.getAtt("DbProxy","Endpoint")};if(N.HttpFunctionName={Description:"HTTP function name",Value:t.ref("HttpFunction")},N.CliFunctionName={Description:"CLI function name",Value:t.ref("CliFunction")},g)N.QueueFunctionName={Description:"Queue function name",Value:t.ref("QueueFunction")};let Se={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${i}-${r})`,Parameters:y?{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:v,Outputs:N},Oe={};for(let O of Object.values(v))Oe[O.Type]=(Oe[O.Type]??0)+1;return{template:Se,functionNames:d,queueNames:p,resourceSummary:Oe}}var wu=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function Cu(e){let a=`php${e.replace(".","")}`;return wu.map((r)=>`${a}-php-${r}`)}function Ul(e,a){let r=`php${e.replace(".","")}`,n=Cu(e).join(" \\\n "),i=`/opt/remi/${r}/root`,o=`/etc/opt/remi/${r}`;return`${a?`FROM almalinux:9 AS ${a}`:"FROM almalinux:9"}
|
|
7286
|
+
${h}`)}let d=u.outputs[0],m=Buffer.from(await d.arrayBuffer()),p="index",g=Ai([{name:`${p}.mjs`,data:m}]);return{zip:g,bundle:m,sha256:Uo(g),handlerFile:p,handlers:{http:r.handlers?.http??`${p}.http`,queue:r.handlers?.queue??`${p}.queue`,cli:r.handlers?.cli??`${p}.cli`},bundleBytes:m.length}}finally{Yi(o,{recursive:!0,force:!0})}}var Eu=["18","20","22"];function ss(e){if(!e)return"22";let a=String(e).match(/(\d+)/);return a?a[1]:"22"}function Bo(e){let a=e.kind??"node";if(a==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(a==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let r=ss(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&Eu.includes(r))return{lambdaRuntime:e.runtime&&e.runtime.startsWith("nodejs")?e.runtime:`nodejs${r}.x`,kind:"node",version:r,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:r,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function Wt(e,a,r){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${a}-${r}-default`}];return e.queues.map((n)=>{if(typeof n==="string")return{name:`${a}-${r}-${n}`};let[i,o]=Object.entries(n)[0];return{name:`${a}-${r}-${i}`,concurrency:o}})}function ha(e,a,r){return Wt(e,a,r).map((n)=>n.name)}function ya(e){let{app:a,environment:r,handlers:n}=e,i=e.config.project.slug,o=Bo(a).lambdaRuntime,c=a.architecture??"x86_64",u=e.config.project.region,d={http:`${i}-${r}-http`,queue:`${i}-${r}-queue`,cli:`${i}-${r}-cli`};if(a.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 m=Wt(a,i,r),p=m.map((O)=>O.name),g=p.length>0,h=a.logRetention??14,y=a.packaging==="image";if(y&&a.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 f=(a.scheduler??"on")!=="off",b=(a.cache?.driver??"dynamodb")==="dynamodb",v=Boolean(a.assets),T=Ro(i,r),I=a.tmpStorage??512,C={},N={},R=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:t.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:t.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${i}-${r}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${i}/${r}/*`),t.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${i}/${r}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[t.sub(`arn:aws:s3:::${T}`),t.sub(`arn:aws:s3:::${T}/*`),...a.storage?.bucket?[t.sub(`arn:aws:s3:::${a.storage.bucket}`),t.sub(`arn:aws:s3:::${a.storage.bucket}/*`)]:[]]}]}}];if(g)R[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:t.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${i}-${r}-*`)});if(b)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:t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${i}-${r}-cache*`)});let k=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(a.vpc?.subnets?.length)k.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(a.lambdaInsights)k.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");C.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${i}-${r}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:k,Policies:R}};let x=(O)=>({TSCLOUD_LAMBDA_MODE:O,TSCLOUD_ENV:r,...a.octane?{TSCLOUD_OCTANE:"1"}:{},...a.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...b?{TSCLOUD_CACHE_TABLE:`${i}-${r}-cache`}:{},...g?{TSCLOUD_QUEUE:p[0]}:{},...a.env??{}}),M=Boolean(a.efs),B=typeof a.efs==="object"?a.efs:{},_=B.mountPath??"/mnt/local",U=M&&!B.accessPointArn,Y=B.accessPointArn??(U?t.getAtt("EfsAccessPoint","Arn"):void 0),q=a.vpc?.subnets??[],Q=q.length>0,V=a.cache?.driver==="elasticache"||a.database?.connection==="aurora-serverless"||Boolean(a.rdsProxy)||M;if(V&&!Q)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let me=Q?{VpcConfig:{SubnetIds:q,SecurityGroupIds:[...a.vpc?.securityGroups??[],...V?[t.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},Me=U?q.map((O,G)=>`EfsMountTarget${G}`):[],vt=M?{FileSystemConfigs:[{Arn:Y,LocalMountPath:_}]}:{};if(M)R[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function Z(O,G,W,K,ne,Ze,ce,Xe=I){C[`${O}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${G}`,RetentionInDays:h}};let Tt=[...e.runtimeLayers??[],...a.lambdaInsights?[a.lambdaInsights.layerArn]:[]],Pt=y?{PackageType:"Image",Code:{ImageUri:t.ref("ImageUri")},...a.kind==="php"?{}:{ImageConfig:{Command:[W]}}}:{Runtime:o,Handler:W,Code:{S3Bucket:t.ref("ArtifactBucket"),S3Key:t.ref("ArtifactKey")},...Tt.length?{Layers:[...new Set(Tt)]}:{}};C[O]={Type:"AWS::Lambda::Function",DependsOn:[`${O}LogGroup`,...Me],Properties:{FunctionName:G,Architectures:[c],MemorySize:ne,Timeout:Ze,Role:t.getAtt("AppRole","Arn"),Environment:{Variables:x(K)},EphemeralStorage:{Size:Xe},...Pt,...ce!==void 0?{ReservedConcurrentExecutions:ce}:{},...me,...vt}}}if(Z("HttpFunction",d.http,n.http,"http",a.memory??1024,a.timeout??28,a.concurrency,I),Z("CliFunction",d.cli,n.cli,"cli",a.cliMemory??1024,a.cliTimeout??900,void 0,a.cliTmpStorage??I),g)Z("QueueFunction",d.queue,n.queue,"queue",a.queueMemory??1024,a.queueTimeout??120,void 0,a.queueTmpStorage??I);let J=(a.provisionedConcurrency??0)>0?a.provisionedConcurrency:0,ee=["HttpFunction","CliFunction",...g?["QueueFunction"]:[]];if(J)for(let O of ee)C[`${O}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:t.ref(O)}},C[`${O}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:t.ref(O),Name:"live",FunctionVersion:t.getAtt(`${O}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:J}}};let pe=(O)=>J?t.ref(`${O}Alias`):t.getAtt(O,"Arn"),te=(O)=>J?t.ref(`${O}Alias`):t.ref(O);C.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${i}-${r}`,ProtocolType:"HTTP"}},C.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:t.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:pe("HttpFunction"),PayloadFormatVersion:"2.0"}},C.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:t.ref("HttpApi"),RouteKey:"$default",Target:t.join("/",["integrations",t.ref("HttpIntegration")])}},C.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},C.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:te("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},N.HttpApiEndpoint={Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint")},N.HttpApiId={Description:"HTTP API id",Value:t.ref("HttpApi")};let oe=(Array.isArray(a.domain)?a.domain:a.domain?[a.domain]:[]).filter(Boolean);if(oe.length){if(!a.certificateArn&&!a.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let O=a.certificateArn;if(!O)C.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:oe[0],...oe.length>1?{SubjectAlternativeNames:oe.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:oe.map((G)=>({DomainName:G,HostedZoneId:a.hostedZoneId}))}},O=t.ref("HttpCertificate");oe.forEach((G,W)=>{let K=`HttpDomain${W}`;if(C[K]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:G,DomainNameConfigurations:[{CertificateArn:O,EndpointType:"REGIONAL"}]}},C[`HttpApiMapping${W}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:t.ref("HttpApi"),DomainName:t.ref(K),Stage:"$default"}},a.hostedZoneId)C[`HttpDomainRecord${W}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a.hostedZoneId,Name:G,Type:"A",AliasTarget:{DNSName:t.getAtt(K,"RegionalDomainName"),HostedZoneId:t.getAtt(K,"RegionalHostedZoneId")}}};N[`CustomDomain${W}`]={Description:`Custom domain ${G}`,Value:G},N[`CustomDomainTarget${W}`]={Description:`Point ${G} (CNAME/alias) at this APIGW regional domain`,Value:t.getAtt(K,"RegionalDomainName")}})}if(g)C.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${i}-${r}-dlq`,MessageRetentionPeriod:1209600}},m.forEach((O,G)=>{let W=`AppQueue${G}`,K=a.queueTimeout??120;C[W]={Type:"AWS::SQS::Queue",Properties:{QueueName:O.name,VisibilityTimeout:Math.min(43200,K*6),RedrivePolicy:{deadLetterTargetArn:t.getAtt("AppQueueDlq","Arn"),maxReceiveCount:a.queueTries??3}}};let ne=O.concurrency??a.queueConcurrency;C[`${W}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:t.getAtt(W,"Arn"),FunctionName:te("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...ne?{ScalingConfig:{MaximumConcurrency:Math.max(2,ne)}}:{}}},N[`QueueUrl${G}`]={Description:`Queue URL: ${O.name}`,Value:t.ref(W)}});if(f)C.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${r}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:pe("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},C.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:te("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.getAtt("SchedulerRule","Arn")}};if(a.warm&&a.warm>0){let O={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},G=(a.warmFunctions??["http"]).filter((W)=>W!=="queue"||g);for(let W of G){let K=W.charAt(0).toUpperCase()+W.slice(1),ne=Math.ceil(a.warm/5),Ze=0;for(let ce=0;ce<ne;ce++){let Xe=Math.min(5,a.warm-Ze);C[`Warmer${K}Rule${ce}`]={Type:"AWS::Events::Rule",Properties:{Name:`${i}-${r}-warmer-${W}-${ce}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Xe},(Tt,Pt)=>({Id:`warm-${W}-${ce}-${Pt}`,Arn:t.getAtt(O[W],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Ze+=Xe}C[`Warmer${K}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:t.ref(O[W]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${i}-${r}-warmer-${W}-*`)}}}}if(b)C.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${i}-${r}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},N.CacheTableName={Description:"DynamoDB cache table",Value:t.ref("CacheTable")};if(v){if(C.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:T,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},C.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${i}-${r}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},C.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:t.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:t.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...a.assetDomain?{Aliases:[a.assetDomain],ViewerCertificate:{AcmCertificateArn:a.assetCertificateArn??t.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},a.assetDomain){if(!a.assetCertificateArn){if(!a.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(u!=="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 ${u}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);C.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:a.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:a.assetDomain,HostedZoneId:a.hostedZoneId}]}}}if(a.hostedZoneId)C.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a.hostedZoneId,Name:a.assetDomain,Type:"A",AliasTarget:{DNSName:t.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};N.AssetDomain={Description:"Custom asset CDN host",Value:a.assetDomain}}C.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:t.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:t.sub(`arn:aws:s3:::${T}/*`),Condition:{StringEquals:{"AWS:SourceArn":t.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},N.AssetsBucketName={Description:"Assets bucket",Value:t.ref("AssetsBucket")},N.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:t.getAtt("AssetsDistribution","DomainName")}}if(a.firewall?.enabled){let O=[],G=0;if(a.firewall.rateLimit)O.push({Name:"rate-limit",Priority:G++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:a.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${r}-rate`}});let W={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let K of a.firewall.rules??[]){let ne=W[K];if(!ne)continue;O.push({Name:`managed-${K}`,Priority:G++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:ne}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${r}-${K}`}})}C.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${i}-${r}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:O,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-${r}-waf`}}},N.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:t.getAtt("WebAcl","Arn")}}if(Q&&V){if(!a.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.");C.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:a.vpc.id,GroupDescription:`${i}-${r} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(U)C.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${i}-${r}-efs`}]}},q.forEach((O,G)=>{C[`EfsMountTarget${G}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:t.ref("EfsFileSystem"),SubnetId:O,SecurityGroups:[t.getAtt("DataSecurityGroup","GroupId")]}}}),C.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:t.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},N.EfsFileSystemId={Description:"EFS file system id",Value:t.ref("EfsFileSystem")};if(a.cache?.driver==="elasticache")C.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${i}-${r} cache subnets`,SubnetIds:q}},C.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${i}-${r}-cache`,ReplicationGroupDescription:`${i}-${r} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},N.CacheEndpoint={Description:"Redis primary endpoint",Value:t.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(a.database?.connection==="aurora-serverless")C.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${i}-${r} db subnets`,SubnetIds:q}},C.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${i}/${r}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},C.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${i}-${r}-db`,DatabaseName:"app",MasterUsername:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:a.database?.minCapacity??0.5,MaxCapacity:a.database?.maxCapacity??4},DBSubnetGroupName:t.ref("DbSubnetGroup"),VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")]}},C.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:t.ref("DbCluster")}},N.DbEndpoint={Description:"Aurora cluster endpoint",Value:t.getAtt("DbCluster","Endpoint.Address")};if(a.rdsProxy&&a.database?.connection==="aurora-serverless")C.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:t.ref("DbSecret")}]}}]}},C.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof a.rdsProxy==="object"&&a.rdsProxy.name?a.rdsProxy.name:`${i}-${r}-proxy`,EngineFamily:"MYSQL",RoleArn:t.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:t.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:q,VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},C.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:t.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[t.ref("DbCluster")]}},N.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:t.getAtt("DbProxy","Endpoint")};if(N.HttpFunctionName={Description:"HTTP function name",Value:t.ref("HttpFunction")},N.CliFunctionName={Description:"CLI function name",Value:t.ref("CliFunction")},g)N.QueueFunctionName={Description:"Queue function name",Value:t.ref("QueueFunction")};let Se={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${i}-${r})`,Parameters:y?{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:C,Outputs:N},Oe={};for(let O of Object.values(C))Oe[O.Type]=(Oe[O.Type]??0)+1;return{template:Se,functionNames:d,queueNames:p,resourceSummary:Oe}}var Cu=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function wu(e){let a=`php${e.replace(".","")}`;return Cu.map((r)=>`${a}-php-${r}`)}function Ul(e,a){let r=`php${e.replace(".","")}`,n=wu(e).join(" \\\n "),i=`/opt/remi/${r}/root`,o=`/etc/opt/remi/${r}`;return`${a?`FROM almalinux:9 AS ${a}`:"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
|
|
@@ -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
|
-
`}function As(){return fr(Ss(bs(import.meta.url)),"runtime-assets")}function Ii(){let e=As(),a=(r)=>fs(fr(e,r),"utf-8");return[{path:"bootstrap",contents:a("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:a("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:a("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:a("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:a("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:Ou(),mode:420}]}function wa(e={}){let a=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:a,CACHE_DRIVER:a,SESSION_DRIVER:a,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 Lu=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];function*br(e){for(let a of ws(e)){let r=Pe(e,a);if(Sr(r).isDirectory())yield*br(r);else yield r}}function Xf(e={}){let a=e.architecture??"x86_64",r=e.platform??(a==="arm64"?"linux/arm64":"linux/amd64"),n=e.onStep??(()=>{}),i=Ts(Pe(Rs(),"tscloud-php-layer-")),o="tscloud-php-layer:build";try{Is(Pe(i,"Dockerfile"),Au(e)),n("Building PHP runtime image (docker)"),ot("docker",["build","--platform",r,"-t","tscloud-php-layer:build",i],{stdio:"inherit"}),n("Extracting /opt/php from image");let c=ot("docker",["create","--platform",r,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),u=Pe(i,"opt");vs(u,{recursive:!0});try{ot("docker",["cp",`${c}:/opt/php`,Pe(u,"php")],{stdio:"inherit"})}finally{ot("docker",["rm",c],{stdio:"ignore"})}if(!Cs(Pe(u,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let d=[];for(let g of br(u)){let h=Ns(u,g).replace(/\\/g,"/"),y=Sr(g).mode&73?493:420;d.push({name:h,data:Es(g),mode:y})}n("Injecting runtime assets");let m=new Set(Ii().map((g)=>g.path)),p=d.filter((g)=>!m.has(g.name));for(let g of Ii())p.push({name:g.path,data:g.contents,mode:g.mode});return n("Packaging layer ZIP"),{zip:Ai(p),architecture:a,fileCount:p.length}}finally{Ps(i,{recursive:!0,force:!0})}}var Mu=[".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 Os(e,a){return a.some((r)=>e===r||e.startsWith(`${r}/`))}function*vr(e,a,r){for(let n of $s(e)){let i=Ms(e,n),o=Cr(a,i).replace(/\\/g,"/");if(Os(o,r))continue;if(Ar(i).isDirectory())yield*vr(i,a,r);else yield i}}function jo(e){if(e.skipBuild)return;let a=La(e.projectRoot??process.cwd()),r=e.app.build??Lu;for(let n of r)e.onStep?.(`build: ${n}`),Ds(n,{stdio:"inherit",cwd:a})}function Vo(e,a=[]){let r=La(e),n=[...Mu,Ao(),...a],i=[];for(let o of vr(r,r,n)){let c=Cr(r,o).replace(/\\/g,"/"),u=(Ar(o).mode&73)!==0;i.push({name:c,data:Ls(o),mode:u?493:420})}return i}function Ca(e){let a=La(e.projectRoot??process.cwd());jo(e),e.onStep?.("packaging application tree");let r=Vo(a,e.exclude);if(!r.length)throw Error(`No files to package under ${a}`);let n=Ai(r),i=e.app.handlers?.http??"public/index.php";return{zip:n,sha256:ks("sha256").update(n).digest("hex"),handlers:{http:i,queue:e.app.handlers?.queue??i,cli:e.app.handlers?.cli??i},fileCount:r.length}}class Gl{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let a=`asset-opt-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.optimizations.set(a,r),r}createImageOptimization(e){let a=`image-opt-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.imageConfigs.set(a,r),r}createSSGConfig(e){let a=`ssg-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.ssgConfigs.set(a,r),r}createPrerenderConfig(e){let a=`prerender-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.prerenderConfigs.set(a,r),r}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 Qf=new Gl;class Kl{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,a){let r=`lifecycle-${Date.now()}-${this.counter++}`,n={id:r,transitions:e,expiration:a};return this.policies.set(r,n),n}enableVersioning(e=!1){let a=`versioning-${Date.now()}-${this.counter++}`,r={id:a,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(a,r),r}createReplicationRule(e,a,r){let n=`replication-${Date.now()}-${this.counter++}`,i={id:n,sourceRegion:e,destRegion:a,destBucket:r};return this.replicationRules.set(n,i),i}createIntelligentTiering(e,a){let r=`tiering-${Date.now()}-${this.counter++}`,n={id:r,archiveDays:e,deepArchiveDays:a};return this.tieringConfigs.set(r,n),n}enableObjectLock(e){let a=`object-lock-${Date.now()}-${this.counter++}`,r={id:a,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(a,r),r}enableTransferAcceleration(e){let a=`transfer-accel-${Date.now()}-${this.counter++}`,r={id:a,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(a,r),r}createAccessPoint(e){let a=`access-point-${Date.now()}-${this.counter++}`,r={id:a,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(a,r),r}createGlacierArchive(e){let a=`glacier-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createInventory(e){let a=`inventory-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createBatchOperation(e){let a=`batch-op-${Date.now()}-${this.counter++}`,r={id:a,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(a,r),r}executeBatchOperation(e){let a=this.batchOps.get(e);if(!a)throw Error(`Batch operation not found: ${e}`);return a.status="in_progress",a.totalObjects=1000,a.processedObjects=0,a}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let a=`event-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createSQSNotification(e){let a=`event-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createSNSNotification(e){let a=`event-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}generateObjectLockCF(e){let a={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)a.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)a.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return a}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 a=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",r=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",n={Event:e.events[0],[r]:e.destination.arn};if(e.filter)n.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[a]:[n]}}}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 Yf=new Kl;class Jl{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,a=30,r=10){let n=`health-${Date.now()}-${this.counter++}`,i={id:n,url:e,interval:a,timeout:r,status:"healthy"};return this.checks.set(n,i),i}createSyntheticMonitor(e,a,r,n){let i=`synthetic-${Date.now()}-${this.counter++}`,o={id:i,name:e,script:a,frequency:r,locations:n};return this.synthetics.set(i,o),o}trackUptime(e,a,r){let n=`uptime-${Date.now()}-${this.counter++}`,i=a/(a+r)*100,o={id:n,resource:e,uptime:a,downtime:r,availability:i};return this.uptimeTrackers.set(n,o),o}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var Zf=new Jl;class Xl{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,a,r,n){let i=`waf-${Date.now()}-${this.counter++}`,o={id:i,name:e,priority:a,action:r,conditions:n};return this.wafRules.set(i,o),o}enableShield(e,a="standard"){let r=`shield-${Date.now()}-${this.counter++}`,n={id:r,resourceArn:e,protectionType:a};return this.shieldProtections.set(r,n),n}createSecurityGroup(e,a,r){let n=`sg-${Date.now()}-${this.counter++}`,i={id:n,name:e,vpcId:a,rules:r};return this.securityGroups.set(n,i),i}createNACL(e,a){let r=`nacl-${Date.now()}-${this.counter++}`,n={id:r,vpcId:e,rules:a};return this.nacls.set(r,n),n}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var eh=new Xl;class Ql{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,a){let r=`tagging-${Date.now()}-${this.counter++}`,n={id:r,tags:e,resources:a};return this.strategies.set(r,n),n}createCostAllocation(e,a){let r=`cost-${Date.now()}-${this.counter++}`,n={id:r,tagKey:e,allocations:a};return this.allocations.set(r,n),n}createResourceGroup(e,a,r){let n=`group-${Date.now()}-${this.counter++}`,i={id:n,name:e,query:{resourceTypeFilters:a,tagFilters:r}};return this.groups.set(n,i),i}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var th=new Ql;export{hc,ae,yc,Nd,bp,hi,vp,Tp,Ws,Ep,wp,Cp,Ap,Ip,Rp,Pp,Sc,bc,Gs,Ks,Ao,et,A,Js,vc,H,Pr,C,Dd,yi,Xs,Qs,F,Io,Np,Dp,kp,_p,l,s,xp,$p,E,Ys,Zs,ea,Op,Lp,De,ta,Ro,kd,Mp,Up,Ue,Et,ra,Tc,Ec,Bp,wc,Cc,Ac,na,Ic,jt,Po,Si,No,bi,Be,_d,Do,ko,ia,oa,sa,aa,ca,la,ve,j,S,L,tt,D,xd,wt,ge,Vt,Fp,$d,Te,_o,Fe,zt,vi,Ee,xo,ke,Od,Ti,we,Ce,re,Ei,X,Ht,Ct,Ae,t,$o,jp,Rc,da,Vp,zp,Hp,qp,ua,Wp,Gp,Kp,Jp,Xp,Qp,Yp,Zp,em,tm,rm,nm,Ld,Md,Ud,Bd,Fd,jd,Vd,qt,Pc,Nc,Nr,wi,im,Dc,om,sm,cn,am,cm,lm,dm,um,pm,zd,Hd,qd,Wd,Gd,Oo,mm,pa,Kd,Jd,Xd,kc,Ie,gm,Qd,At,Lo,Dr,Yd,_c,Zd,eu,tu,xc,_e,fm,hm,ym,Sm,ru,bm,Re,vm,Tm,Em,$c,Oc,wm,Lc,Mc,Cm,Am,Im,Rm,Pm,nu,ma,Nm,Dm,km,_m,xm,iu,ou,$m,Om,Lm,Mm,Um,Bm,Fm,jm,Vm,Uc,ga,zm,Hm,qm,Wm,Bc,Fc,jc,Gm,Vc,Km,Jm,Xm,Qm,zc,Ym,Zm,eg,tg,rg,ng,ig,og,su,au,cu,lu,Hc,sg,ag,cg,lg,dg,ug,pg,mg,gg,du,uu,pu,mu,fg,hg,qc,yg,Wc,Gc,Kc,Jc,Sg,bg,vg,Tg,rt,Ci,Eg,wg,Cg,Ag,Ig,Rg,Pg,Ng,gu,Dg,kg,Xc,Qc,_g,xg,fu,$g,Og,Lg,Mg,Ug,Bg,Fg,jg,Vg,zg,Hg,qg,Wg,Gg,Kg,Jg,Xg,Qg,Yg,Zg,ef,Yc,tf,Zc,rf,el,nf,tl,of,rl,sf,ln,af,nl,cf,Mo,lf,il,df,ol,uf,sl,pf,al,mf,cl,gf,dn,ff,ll,hf,dl,yf,ul,Sf,pl,bf,ml,vf,gl,Tf,fl,Ef,hl,wf,yl,Cf,Sl,Af,bl,If,vl,Rf,Tl,Pf,El,Nf,wl,Df,Cl,kf,Al,_f,Il,xf,Rl,$f,Pl,Of,Nl,Lf,Dl,Mf,kl,Uf,_l,Bf,xl,Ff,hu,yu,Su,bu,$l,jf,Ol,Vf,Ll,zf,Ml,Hf,Ai,vu,Tu,Uo,fa,un,Eu,Bo,Wt,ha,ya,wu,Cu,Ul,Au,Sa,Bl,qf,Wf,ba,va,Ta,Fl,Fo,jl,Vl,Ea,zl,Hl,ql,Iu,Ru,Pu,Gf,Nu,Du,Kf,ku,Wl,_u,xu,$u,Jf,Ou,Ii,wa,Lu,Xf,Mu,jo,Vo,Ca,Gl,Qf,Kl,Yf,Jl,Zf,Xl,eh,Ql,th};
|
|
7364
|
+
`}function As(){return fr(Ss(bs(import.meta.url)),"runtime-assets")}function Ii(){let e=As(),a=(r)=>fs(fr(e,r),"utf-8");return[{path:"bootstrap",contents:a("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:a("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:a("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:a("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:a("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:Ou(),mode:420}]}function Ca(e={}){let a=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:a,CACHE_DRIVER:a,SESSION_DRIVER:a,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 Lu=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];function*br(e){for(let a of ws(e)){let r=Pe(e,a);if(Sr(r).isDirectory())yield*br(r);else yield r}}function Xf(e={}){let a=e.architecture??"x86_64",r=e.platform??(a==="arm64"?"linux/arm64":"linux/amd64"),n=e.onStep??(()=>{}),i=Ts(Pe(Rs(),"tscloud-php-layer-")),o="tscloud-php-layer:build";try{Is(Pe(i,"Dockerfile"),Au(e)),n("Building PHP runtime image (docker)"),ot("docker",["build","--platform",r,"-t","tscloud-php-layer:build",i],{stdio:"inherit"}),n("Extracting /opt/php from image");let c=ot("docker",["create","--platform",r,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),u=Pe(i,"opt");vs(u,{recursive:!0});try{ot("docker",["cp",`${c}:/opt/php`,Pe(u,"php")],{stdio:"inherit"})}finally{ot("docker",["rm",c],{stdio:"ignore"})}if(!Cs(Pe(u,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let d=[];for(let g of br(u)){let h=Ns(u,g).replace(/\\/g,"/"),y=Sr(g).mode&73?493:420;d.push({name:h,data:Es(g),mode:y})}n("Injecting runtime assets");let m=new Set(Ii().map((g)=>g.path)),p=d.filter((g)=>!m.has(g.name));for(let g of Ii())p.push({name:g.path,data:g.contents,mode:g.mode});return n("Packaging layer ZIP"),{zip:Ai(p),architecture:a,fileCount:p.length}}finally{Ps(i,{recursive:!0,force:!0})}}var Mu=[".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 Os(e,a){return a.some((r)=>e===r||e.startsWith(`${r}/`))}function*vr(e,a,r){for(let n of $s(e)){let i=Ms(e,n),o=Cr(a,i).replace(/\\/g,"/");if(Os(o,r))continue;if(Ar(i).isDirectory())yield*vr(i,a,r);else yield i}}function jo(e){if(e.skipBuild)return;let a=La(e.projectRoot??process.cwd()),r=e.app.build??Lu;for(let n of r)e.onStep?.(`build: ${n}`),Ds(n,{stdio:"inherit",cwd:a})}function Vo(e,a=[]){let r=La(e),n=[...Mu,Ao(),...a],i=[];for(let o of vr(r,r,n)){let c=Cr(r,o).replace(/\\/g,"/"),u=(Ar(o).mode&73)!==0;i.push({name:c,data:Ls(o),mode:u?493:420})}return i}function wa(e){let a=La(e.projectRoot??process.cwd());jo(e),e.onStep?.("packaging application tree");let r=Vo(a,e.exclude);if(!r.length)throw Error(`No files to package under ${a}`);let n=Ai(r),i=e.app.handlers?.http??"public/index.php";return{zip:n,sha256:ks("sha256").update(n).digest("hex"),handlers:{http:i,queue:e.app.handlers?.queue??i,cli:e.app.handlers?.cli??i},fileCount:r.length}}class Gl{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let a=`asset-opt-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.optimizations.set(a,r),r}createImageOptimization(e){let a=`image-opt-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.imageConfigs.set(a,r),r}createSSGConfig(e){let a=`ssg-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.ssgConfigs.set(a,r),r}createPrerenderConfig(e){let a=`prerender-${Date.now()}-${this.counter++}`,r={id:a,...e};return this.prerenderConfigs.set(a,r),r}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 Qf=new Gl;class Kl{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,a){let r=`lifecycle-${Date.now()}-${this.counter++}`,n={id:r,transitions:e,expiration:a};return this.policies.set(r,n),n}enableVersioning(e=!1){let a=`versioning-${Date.now()}-${this.counter++}`,r={id:a,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(a,r),r}createReplicationRule(e,a,r){let n=`replication-${Date.now()}-${this.counter++}`,i={id:n,sourceRegion:e,destRegion:a,destBucket:r};return this.replicationRules.set(n,i),i}createIntelligentTiering(e,a){let r=`tiering-${Date.now()}-${this.counter++}`,n={id:r,archiveDays:e,deepArchiveDays:a};return this.tieringConfigs.set(r,n),n}enableObjectLock(e){let a=`object-lock-${Date.now()}-${this.counter++}`,r={id:a,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(a,r),r}enableTransferAcceleration(e){let a=`transfer-accel-${Date.now()}-${this.counter++}`,r={id:a,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(a,r),r}createAccessPoint(e){let a=`access-point-${Date.now()}-${this.counter++}`,r={id:a,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(a,r),r}createGlacierArchive(e){let a=`glacier-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createInventory(e){let a=`inventory-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createBatchOperation(e){let a=`batch-op-${Date.now()}-${this.counter++}`,r={id:a,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(a,r),r}executeBatchOperation(e){let a=this.batchOps.get(e);if(!a)throw Error(`Batch operation not found: ${e}`);return a.status="in_progress",a.totalObjects=1000,a.processedObjects=0,a}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let a=`event-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createSQSNotification(e){let a=`event-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}createSNSNotification(e){let a=`event-${Date.now()}-${this.counter++}`,r={id:a,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(a,r),r}generateObjectLockCF(e){let a={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)a.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)a.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return a}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 a=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",r=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",n={Event:e.events[0],[r]:e.destination.arn};if(e.filter)n.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[a]:[n]}}}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 Yf=new Kl;class Jl{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,a=30,r=10){let n=`health-${Date.now()}-${this.counter++}`,i={id:n,url:e,interval:a,timeout:r,status:"healthy"};return this.checks.set(n,i),i}createSyntheticMonitor(e,a,r,n){let i=`synthetic-${Date.now()}-${this.counter++}`,o={id:i,name:e,script:a,frequency:r,locations:n};return this.synthetics.set(i,o),o}trackUptime(e,a,r){let n=`uptime-${Date.now()}-${this.counter++}`,i=a/(a+r)*100,o={id:n,resource:e,uptime:a,downtime:r,availability:i};return this.uptimeTrackers.set(n,o),o}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var Zf=new Jl;class Xl{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,a,r,n){let i=`waf-${Date.now()}-${this.counter++}`,o={id:i,name:e,priority:a,action:r,conditions:n};return this.wafRules.set(i,o),o}enableShield(e,a="standard"){let r=`shield-${Date.now()}-${this.counter++}`,n={id:r,resourceArn:e,protectionType:a};return this.shieldProtections.set(r,n),n}createSecurityGroup(e,a,r){let n=`sg-${Date.now()}-${this.counter++}`,i={id:n,name:e,vpcId:a,rules:r};return this.securityGroups.set(n,i),i}createNACL(e,a){let r=`nacl-${Date.now()}-${this.counter++}`,n={id:r,vpcId:e,rules:a};return this.nacls.set(r,n),n}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var eh=new Xl;class Ql{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,a){let r=`tagging-${Date.now()}-${this.counter++}`,n={id:r,tags:e,resources:a};return this.strategies.set(r,n),n}createCostAllocation(e,a){let r=`cost-${Date.now()}-${this.counter++}`,n={id:r,tagKey:e,allocations:a};return this.allocations.set(r,n),n}createResourceGroup(e,a,r){let n=`group-${Date.now()}-${this.counter++}`,i={id:n,name:e,query:{resourceTypeFilters:a,tagFilters:r}};return this.groups.set(n,i),i}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var th=new Ql;export{hc,ae,yc,Nd,bp,hi,vp,Tp,Ws,Ep,Cp,wp,Ap,Ip,Rp,Pp,Sc,bc,Gs,Ks,Ao,et,A,Js,vc,H,Pr,w,Dd,yi,Xs,Qs,F,Io,Np,Dp,kp,_p,l,s,xp,$p,E,Ys,Zs,ea,Op,Lp,De,ta,Ro,kd,Mp,Up,Ue,Et,ra,Tc,Ec,Bp,Cc,wc,Ac,na,Ic,jt,Po,Si,No,bi,Be,_d,Do,ko,ia,oa,sa,aa,ca,la,ve,j,S,L,tt,D,xd,Ct,ge,Vt,Fp,$d,Te,_o,Fe,zt,vi,Ee,xo,ke,Od,Ti,Ce,we,re,Ei,X,Ht,wt,Ae,t,$o,jp,Rc,da,Vp,zp,Hp,qp,ua,Wp,Gp,Kp,Jp,Xp,Qp,Yp,Zp,em,tm,rm,nm,Ld,Md,Ud,Bd,Fd,jd,Vd,qt,Pc,Nc,Nr,Ci,im,Dc,om,sm,cn,am,cm,lm,dm,um,pm,zd,Hd,qd,Wd,Gd,Oo,mm,pa,Kd,Jd,Xd,kc,Ie,gm,Qd,At,Lo,Dr,Yd,_c,Zd,eu,tu,xc,_e,fm,hm,ym,Sm,ru,bm,Re,vm,Tm,Em,$c,Oc,Cm,Lc,Mc,wm,Am,Im,Rm,Pm,nu,ma,Nm,Dm,km,_m,xm,iu,ou,$m,Om,Lm,Mm,Um,Bm,Fm,jm,Vm,Uc,ga,zm,Hm,qm,Wm,Bc,Fc,jc,Gm,Vc,Km,Jm,Xm,Qm,zc,Ym,Zm,eg,tg,rg,ng,ig,og,su,au,cu,lu,Hc,sg,ag,cg,lg,dg,ug,pg,mg,gg,du,uu,pu,mu,fg,hg,qc,yg,Wc,Gc,Kc,Jc,Sg,bg,vg,Tg,rt,wi,Eg,Cg,wg,Ag,Ig,Rg,Pg,Ng,gu,Dg,kg,Xc,Qc,_g,xg,fu,$g,Og,Lg,Mg,Ug,Bg,Fg,jg,Vg,zg,Hg,qg,Wg,Gg,Kg,Jg,Xg,Qg,Yg,Zg,ef,Yc,tf,Zc,rf,el,nf,tl,of,rl,sf,ln,af,nl,cf,Mo,lf,il,df,ol,uf,sl,pf,al,mf,cl,gf,dn,ff,ll,hf,dl,yf,ul,Sf,pl,bf,ml,vf,gl,Tf,fl,Ef,hl,Cf,yl,wf,Sl,Af,bl,If,vl,Rf,Tl,Pf,El,Nf,Cl,Df,wl,kf,Al,_f,Il,xf,Rl,$f,Pl,Of,Nl,Lf,Dl,Mf,kl,Uf,_l,Bf,xl,Ff,hu,yu,Su,bu,$l,jf,Ol,Vf,Ll,zf,Ml,Hf,Ai,vu,Tu,Uo,fa,un,Eu,Bo,Wt,ha,ya,Cu,wu,Ul,Au,Sa,Bl,qf,Wf,ba,va,Ta,Fl,Fo,jl,Vl,Ea,zl,Hl,ql,Iu,Ru,Pu,Gf,Nu,Du,Kf,ku,Wl,_u,xu,$u,Jf,Ou,Ii,Ca,Lu,Xf,Mu,jo,Vo,wa,Gl,Qf,Kl,Yf,Jl,Zf,Xl,eh,Ql,th};
|