@stacksjs/ts-cloud 0.12.1 → 0.12.3
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-0zwknfwp.js +1 -0
- package/dist/bin/chunk-3aph4c1w.js +2 -0
- package/dist/bin/{chunk-5bhx3bsa.js → chunk-4q6tad44.js} +121 -121
- package/dist/bin/chunk-5nkqza92.js +1 -0
- package/dist/bin/chunk-64vczwwt.js +1 -0
- package/dist/bin/chunk-6tfwm33r.js +6 -0
- package/dist/bin/chunk-71t1gmsq.js +1 -0
- package/dist/bin/chunk-7g2ahkse.js +1 -0
- package/dist/bin/chunk-7zhgmp1s.js +3 -0
- package/dist/bin/chunk-82mj52xr.js +141 -0
- package/dist/bin/chunk-8ewncfce.js +37 -0
- package/dist/bin/chunk-9a88fp00.js +2 -0
- package/dist/bin/chunk-9kf0np8j.js +44 -0
- package/dist/bin/chunk-9rb23kz9.js +1 -0
- package/dist/bin/chunk-a7w13qfm.js +2 -0
- package/dist/bin/chunk-b4wt9jcg.js +60 -0
- package/dist/bin/chunk-btsyjhk7.js +92 -0
- package/dist/bin/chunk-c0bdafbx.js +2 -0
- package/dist/bin/chunk-cd0ps58j.js +1 -0
- package/dist/bin/chunk-cxt74wsj.js +1 -0
- package/dist/bin/chunk-d7ke90zt.js +2 -0
- package/dist/bin/chunk-djg4zyqk.js +1 -0
- package/dist/bin/chunk-dkaz333b.js +1 -0
- package/dist/bin/chunk-dkf4qsp2.js +1 -0
- package/dist/bin/{chunk-scqmd4qv.js → chunk-dz1ec589.js} +30 -30
- package/dist/bin/chunk-e2bybahr.js +3 -0
- package/dist/bin/chunk-e5ab5twy.js +50 -0
- package/dist/bin/chunk-edvvx3hg.js +1 -0
- package/dist/bin/chunk-ehc63fvs.js +2 -0
- package/dist/bin/chunk-f06c5np9.js +1 -0
- package/dist/bin/chunk-gq8794k6.js +1 -0
- package/dist/bin/chunk-hq9x489e.js +70 -0
- package/dist/bin/chunk-ja1vjdn1.js +6 -0
- package/dist/bin/chunk-k3120rx6.js +1 -0
- package/dist/bin/chunk-kg61p5hw.js +3 -0
- package/dist/bin/chunk-mcr0r4at.js +2 -0
- package/dist/bin/chunk-mfrf9q4b.js +2 -0
- package/dist/bin/chunk-my3ewh3a.js +34 -0
- package/dist/bin/chunk-nw3d4k52.js +1 -0
- package/dist/bin/chunk-p70bc9yr.js +1 -0
- package/dist/bin/chunk-pp2m8q55.js +512 -0
- package/dist/bin/chunk-q5cmfpzt.js +1 -0
- package/dist/bin/chunk-rtecnmts.js +4 -0
- package/dist/bin/chunk-s2grgcpy.js +590 -0
- package/dist/bin/chunk-s4yzes15.js +2 -0
- package/dist/bin/chunk-sj5csg49.js +2 -0
- package/dist/bin/chunk-tfbs8k8v.js +111 -0
- package/dist/bin/chunk-tvz9c388.js +1 -0
- package/dist/bin/{chunk-9vdc7adf.js → chunk-w32xv8n4.js} +6 -6
- package/dist/bin/chunk-x6f61g36.js +9 -0
- package/dist/bin/chunk-xhwqpgwq.js +2 -0
- package/dist/bin/chunk-xk08030d.js +6 -0
- package/dist/bin/chunk-xkfrqqcs.js +1 -0
- package/dist/bin/chunk-y1h63vpm.js +1 -0
- package/dist/bin/chunk-zdt2rjk6.js +1 -0
- package/dist/bin/chunk-zh2d4704.js +1 -0
- package/dist/bin/chunk-zpe64t4r.js +1 -0
- package/dist/bin/cli.js +435 -444
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/{chunk-rr1yaj55.js → chunk-13qjvbqh.js} +1 -1
- package/dist/chunk-152he7m3.js +92 -0
- package/dist/chunk-1qdne0bf.js +1 -0
- package/dist/chunk-3mgj3hrh.js +5 -0
- package/dist/chunk-3nmm7cap.js +704 -0
- package/dist/chunk-6kpbveb8.js +5 -0
- package/dist/chunk-73ztr55z.js +2 -0
- package/dist/{chunk-y1dh3znq.js → chunk-86ss83s2.js} +52 -52
- package/dist/chunk-a84gmpyh.js +1 -0
- package/dist/chunk-aj025v2s.js +4 -0
- package/dist/chunk-by2bwzk6.js +141 -0
- package/dist/chunk-h42zck7h.js +60 -0
- package/dist/chunk-hn40z11p.js +37 -0
- package/dist/{chunk-6xcbfs2r.js → chunk-jm5mg890.js} +111 -111
- package/dist/chunk-m8fs0233.js +34 -0
- package/dist/chunk-mz0dk78z.js +6 -0
- package/dist/chunk-n514hj0z.js +450 -0
- package/dist/chunk-nms5q44e.js +1 -0
- package/dist/chunk-qm32ytbr.js +1 -0
- package/dist/chunk-t0xgmhd6.js +114 -0
- package/dist/chunk-t3t9ymec.js +1 -0
- package/dist/chunk-tz9myq9a.js +2 -0
- package/dist/chunk-wavjkdb8.js +2 -0
- package/dist/chunk-x3hay61c.js +44 -0
- package/dist/chunk-xcj8zfmg.js +2 -0
- package/dist/chunk-y2v22hkv.js +1 -0
- package/dist/chunk-y4xkj2f1.js +50 -0
- package/dist/deploy/index.js +1 -1
- package/dist/dns/index.js +1 -1
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/shared/deploy-script.d.ts +85 -0
- package/dist/index.js +90 -90
- package/dist/protection/index.js +1 -1
- package/dist/push/index.js +1 -1
- package/dist/spend/index.js +1 -1
- package/dist/ui/404.html +2 -2
- package/dist/ui/_stx/{router.fa5bc4dc.js → router.229f89ab.js} +1 -1
- package/dist/ui/_stx/runtime.dbee66d1.js +1 -0
- package/dist/ui/accept-invitation.html +2 -2
- 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 +80 -80
- package/dist/ui/data/services.html +78 -78
- package/dist/ui/data/volumes.html +50 -50
- package/dist/ui/index.html +50 -50
- package/dist/ui/infrastructure/topology.html +118 -118
- package/dist/ui/integrations.html +1 -1
- package/dist/ui/operations/alerts.html +48 -48
- package/dist/ui/operations/configuration.html +5 -5
- package/dist/ui/operations/jobs.html +75 -75
- package/dist/ui/operations/maintenance.html +6 -6
- package/dist/ui/operations/observability.html +82 -82
- package/dist/ui/operations/previews.html +6 -6
- 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 +54 -54
- package/dist/ui/operations/workloads.html +104 -104
- package/dist/ui/security.html +1 -1
- package/dist/ui/server/actions.html +56 -56
- package/dist/ui/server/activity.html +2 -2
- package/dist/ui/server/capacity.html +6 -6
- package/dist/ui/server/database.html +105 -105
- package/dist/ui/server/deployments.html +50 -50
- package/dist/ui/server/diagnostics.html +2 -2
- package/dist/ui/server/firewall.html +76 -76
- package/dist/ui/server/fleet.html +34 -34
- package/dist/ui/server/logs.html +24 -24
- package/dist/ui/server/metrics.html +112 -112
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +27 -27
- package/dist/ui/server/sites.html +120 -120
- package/dist/ui/server/ssh-keys.html +52 -52
- package/dist/ui/server/team.html +144 -144
- package/dist/ui/server/terminal.html +15 -15
- package/dist/ui/serverless/alarms.html +52 -52
- package/dist/ui/serverless/assets.html +28 -28
- package/dist/ui/serverless/cost.html +2 -2
- package/dist/ui/serverless/data.html +36 -36
- package/dist/ui/serverless/deployments.html +28 -28
- package/dist/ui/serverless/firewall.html +2 -2
- package/dist/ui/serverless/functions.html +40 -40
- package/dist/ui/serverless/logs.html +23 -23
- package/dist/ui/serverless/metrics.html +2 -2
- package/dist/ui/serverless/queues.html +48 -48
- package/dist/ui/serverless/secrets.html +52 -52
- package/dist/ui/serverless/traces.html +6 -6
- package/dist/ui/serverless.html +53 -53
- package/dist/ui-src/src/charts.ts +4644 -16118
- package/dist/ui-src/src/topology.ts +2 -2
- package/package.json +6 -6
- package/dist/bin/chunk-0rtn6q5x.js +0 -3
- package/dist/bin/chunk-258ehp9s.js +0 -1
- package/dist/bin/chunk-2yctv06c.js +0 -1
- package/dist/bin/chunk-3276rveh.js +0 -37
- package/dist/bin/chunk-3m665jwp.js +0 -70
- package/dist/bin/chunk-3s2p9vxj.js +0 -1
- package/dist/bin/chunk-4esma5m9.js +0 -1
- package/dist/bin/chunk-4n0j3n3b.js +0 -2
- package/dist/bin/chunk-54bqchag.js +0 -92
- package/dist/bin/chunk-5zagqd20.js +0 -1
- package/dist/bin/chunk-7hw2js5h.js +0 -512
- package/dist/bin/chunk-8h1qr6x4.js +0 -50
- package/dist/bin/chunk-a1dd6sby.js +0 -1
- package/dist/bin/chunk-a4dw35gs.js +0 -1
- package/dist/bin/chunk-a9d55ker.js +0 -1
- package/dist/bin/chunk-awa1qade.js +0 -9
- package/dist/bin/chunk-b6by94pk.js +0 -2
- package/dist/bin/chunk-c8sypnbe.js +0 -2
- package/dist/bin/chunk-cx4e3d4w.js +0 -1
- package/dist/bin/chunk-d5a3vheh.js +0 -2
- package/dist/bin/chunk-e1fym2bd.js +0 -1
- package/dist/bin/chunk-ej4h0q2y.js +0 -1
- package/dist/bin/chunk-ett305ym.js +0 -4
- package/dist/bin/chunk-f11xf3n6.js +0 -2
- package/dist/bin/chunk-fq7ktvgy.js +0 -3
- package/dist/bin/chunk-fyq4th2m.js +0 -1
- package/dist/bin/chunk-g67qr8yf.js +0 -1
- package/dist/bin/chunk-gc82cx4h.js +0 -1
- package/dist/bin/chunk-hchtvpr9.js +0 -1
- package/dist/bin/chunk-hpe4jjce.js +0 -1
- package/dist/bin/chunk-k5vprsef.js +0 -6
- package/dist/bin/chunk-m22krd4z.js +0 -3
- package/dist/bin/chunk-mkppcwz8.js +0 -1
- package/dist/bin/chunk-mpjg0kc7.js +0 -2
- package/dist/bin/chunk-mrm4m4dk.js +0 -2
- package/dist/bin/chunk-nff46rxd.js +0 -1
- package/dist/bin/chunk-np1z3bgt.js +0 -1
- package/dist/bin/chunk-nskxkk6r.js +0 -1
- package/dist/bin/chunk-pez932b1.js +0 -111
- package/dist/bin/chunk-qsdf5kzk.js +0 -2
- package/dist/bin/chunk-r61qmhv1.js +0 -2
- package/dist/bin/chunk-r6gdcz5c.js +0 -1
- package/dist/bin/chunk-satwnr42.js +0 -2
- package/dist/bin/chunk-smbycpt5.js +0 -44
- package/dist/bin/chunk-sn7e0sn7.js +0 -2
- package/dist/bin/chunk-ss574pka.js +0 -1
- package/dist/bin/chunk-tj0xb2d8.js +0 -585
- package/dist/bin/chunk-v3rzf9d0.js +0 -141
- package/dist/bin/chunk-wnpma6t3.js +0 -34
- package/dist/bin/chunk-xan0e052.js +0 -5
- package/dist/bin/chunk-xbk2y43r.js +0 -60
- package/dist/bin/chunk-xjp3v95e.js +0 -6
- package/dist/bin/chunk-xyt490vp.js +0 -6
- package/dist/bin/chunk-yn9r02gy.js +0 -1
- package/dist/bin/chunk-zhkhn9cc.js +0 -1
- package/dist/chunk-0zf72ngj.js +0 -1
- package/dist/chunk-2hpjte1d.js +0 -704
- package/dist/chunk-4m6gwhwr.js +0 -5
- package/dist/chunk-5m29dhke.js +0 -34
- package/dist/chunk-6fzeemcs.js +0 -114
- package/dist/chunk-bpnhqb70.js +0 -6
- package/dist/chunk-ead1nkbr.js +0 -60
- package/dist/chunk-fea461tj.js +0 -141
- package/dist/chunk-fvjczc73.js +0 -1
- package/dist/chunk-gearw6rk.js +0 -4
- package/dist/chunk-j60hesb3.js +0 -2
- package/dist/chunk-pmgtmt3d.js +0 -1
- package/dist/chunk-prf2pkvq.js +0 -5
- package/dist/chunk-q0wffgw5.js +0 -37
- package/dist/chunk-qcemnt35.js +0 -50
- package/dist/chunk-qvbwsaay.js +0 -1
- package/dist/chunk-r2pbqcnz.js +0 -2
- package/dist/chunk-r6110zv2.js +0 -1
- package/dist/chunk-wcrj06cg.js +0 -44
- package/dist/chunk-wte9mh18.js +0 -92
- package/dist/chunk-y6e86wjs.js +0 -445
- package/dist/chunk-y8b7ht4v.js +0 -1
- package/dist/chunk-yf487g6e.js +0 -2
- package/dist/chunk-zmmc9j5f.js +0 -2
- package/dist/ui/_stx/runtime.c696d17a.js +0 -1
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import{Et as
|
|
2
|
-
`),O=
|
|
3
|
-
`),j=e.cache??
|
|
4
|
-
`),
|
|
5
|
-
`),
|
|
6
|
-
`,E=
|
|
7
|
-
`),P=[p,l,m,
|
|
8
|
-
`),N=
|
|
9
|
-
`,E=
|
|
10
|
-
`),P=[p,l,m,await
|
|
11
|
-
`),N=await xa(i,u,c,o,P,h??
|
|
1
|
+
import{Et as ye}from"./chunk-13qjvbqh.js";import{createRequire as Ln}from"node:module";import{isAbsolute as Gt,join as St,relative as Jn}from"node:path";import{existsSync as je,readdirSync as li}from"node:fs";import{join as Ae}from"node:path";import{createHash as Ii}from"node:crypto";import{copyFileSync as Ri,existsSync as Lt,readdirSync as Ni,readFileSync as st,statSync as Di,writeFileSync as ot}from"node:fs";import{basename as ki,dirname as ma,extname as pa,join as Ke}from"node:path";import{existsSync as Ya,readFileSync as zt}from"node:fs";import{homedir as Za}from"node:os";import{join as Xa}from"node:path";import{createHash as ar}from"node:crypto";import{existsSync as lt,mkdirSync as qs,readdirSync as Aa,readFileSync as Ca,unlinkSync as He,writeFileSync as zs}from"node:fs";import{join as xt}from"node:path";import{createHash as Qt}from"node:crypto";import{createReadStream as Qs,readdirSync as Js,statSync as At}from"node:fs";import{join as Ys,relative as Zs}from"node:path";import{deflateRawSync as Po}from"node:zlib";import{execSync as $o}from"node:child_process";import{createHash as Lo}from"node:crypto";import{cpSync as Mo,mkdtempSync as xo,rmSync as Oo,writeFileSync as Bo}from"node:fs";import{tmpdir as _o}from"node:os";import{dirname as Wo,isAbsolute as Go,join as Le,resolve as Fo}from"node:path";import{fileURLToPath as Vo}from"node:url";import{execFileSync as It}from"node:child_process";import{mkdtempSync as mn,readFileSync as Rt,rmSync as pn}from"node:fs";import{tmpdir as gn}from"node:os";import{dirname as Xo,join as ve}from"node:path";import{fileURLToPath as ec}from"node:url";import{AsyncLocalStorage as ac}from"node:async_hooks";import{createHash as rc}from"node:crypto";import{readFileSync as wc}from"node:fs";import{dirname as Ec,join as Tn}from"node:path";import{fileURLToPath as Pc}from"node:url";import{execFileSync as ut}from"node:child_process";import{existsSync as Nc,mkdirSync as Dc,mkdtempSync as kc,readdirSync as $c,readFileSync as Lc,rmSync as Mc,statSync as vn,writeFileSync as xc}from"node:fs";import{tmpdir as Oc}from"node:os";import{join as Me,relative as Bc}from"node:path";import{execSync as _c}from"node:child_process";import{createHash as Wc}from"node:crypto";import{readdirSync as Gc,readFileSync as Fc,statSync as En}from"node:fs";import{join as Vc,relative as Pn,resolve as da}from"node:path";var Mn=Object.defineProperty,xn=(e)=>e;function On(e,t){this[e]=xn.bind(null,t)}var De=(e,t)=>{for(var a in t)Mn(e,a,{get:t[a],enumerable:!0,configurable:!0,set:On.bind(t,a)})},Bn=(e,t)=>()=>(e&&(t=e(e=0)),t),_n=Ln(import.meta.url),Na={};De(Na,{clearSigningKeyCache:()=>Hn,createPresignedUrl:()=>Da,createPresignedUrlAsync:()=>Fn,detectServiceRegion:()=>jt,getSigningKeyCacheSize:()=>qn,isNodeCryptoAvailable:()=>zn,isWebCryptoAvailable:()=>Qn,makeAWSRequest:()=>Ba,makeAWSRequestAsync:()=>Un,makeAWSRequestOnce:()=>Vn,parseJSONResponse:()=>Kn,parseXMLResponse:()=>jn,signRequest:()=>K,signRequestAsync:()=>Kt});function jt(e){let t=typeof e==="string"?new URL(e):e,{hostname:a,pathname:r}=t;if(a.endsWith(".on.aws")){let o=a.match(/^[^.]+\.lambda-url\.([^.]+)\.on\.aws$/);if(o)return{service:"lambda",region:o[1]};return{service:"",region:""}}if(a.endsWith(".r2.cloudflarestorage.com"))return{service:"s3",region:"auto"};if(a.endsWith(".backblazeb2.com")){let o=a.match(/^(?:[^.]+\.)?s3\.([^.]+)\.backblazeb2\.com$/);if(o)return{service:"s3",region:o[1]};return{service:"",region:""}}let n=a.replace("dualstack.","").match(/([^.]+)\.(?:([^.]+)\.)?amazonaws\.com(?:\.cn)?$/);if(!n)return{service:"",region:""};let i=n[1],s=n[2]||"";if(s==="us-gov")s="us-gov-west-1";else if(s==="s3"||s==="s3-accelerate")s="us-east-1",i="s3";else if(i==="iot")if(a.startsWith("iot."))i="execute-api";else if(a.startsWith("data.jobs.iot."))i="iot-jobs-data";else i=r==="/mqtt"?"iotdevicegateway":"iotdata";else if(i==="autoscaling");else if(!s&&i.startsWith("s3-"))s=i.slice(3).replace(/^fips-|^external-1/,""),i="s3";else if(i.endsWith("-fips"))i=i.slice(0,-5);else if(s&&/-\d$/.test(i)&&!/-\d$/.test(s))[i,s]=[s,i];return i=Wa[i]||i,{service:i,region:s||"us-east-1"}}function K(e){let{method:t,url:a,body:r="",accessKeyId:n,secretAccessKey:i,sessionToken:s,signQuery:o=!1,expiresIn:c=86400,datetime:l}=e,u=new URL(a),m=u.hostname,p=jt(u),g=e.service||p.service,h=e.region||p.region;if(!g)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!h)throw Error("Could not detect region from URL. Please provide region explicitly.");let y=l||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),b=y.substring(0,8),T=[b,h,g,"aws4_request"].join("/"),w="AWS4-HMAC-SHA256";if(o)return Wn({urlObj:u,method:t,body:r,accessKeyId:n,secretAccessKey:i,sessionToken:s,service:g,region:h,timestamp:y,date:b,credentialScope:T,algorithm:w,expiresIn:c,cache:e.cache});let S=u.pathname||"/",E=vt(u.searchParams),v={host:m,"x-amz-date":y,...e.headers};if(s)v["x-amz-security-token"]=s;let P=Object.keys(v).some((we)=>we.toLowerCase()==="content-type");if(r&&!P)v["content-type"]="application/x-amz-json-1.0";if(g==="s3"&&!v["x-amz-content-sha256"])v["x-amz-content-sha256"]=Ze(r);let N=ka(v),I=$a(v),D=v["x-amz-content-sha256"]||Ze(r),L=[t,wt(S),E,N,I,D].join(`
|
|
2
|
+
`),O=Ze(L),ce=[w,y,T,O].join(`
|
|
3
|
+
`),j=e.cache??ke,ae=Ma(i,b,h,g,ce,j),F=[`${w} Credential=${n}/${T}`,`SignedHeaders=${I}`,`Signature=${ae}`].join(", ");return v.authorization=F,{url:a,method:t,headers:v,body:r||void 0}}async function Kt(e){let{method:t,url:a,body:r="",accessKeyId:n,secretAccessKey:i,sessionToken:s,signQuery:o=!1,expiresIn:c=86400,datetime:l}=e,u=new URL(a),m=u.hostname,p=jt(u),g=e.service||p.service,h=e.region||p.region;if(!g)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!h)throw Error("Could not detect region from URL. Please provide region explicitly.");let y=l||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),b=y.substring(0,8),T=[b,h,g,"aws4_request"].join("/"),w="AWS4-HMAC-SHA256";if(o)return Gn({urlObj:u,method:t,body:r,accessKeyId:n,secretAccessKey:i,sessionToken:s,service:g,region:h,timestamp:y,date:b,credentialScope:T,algorithm:w,expiresIn:c,cache:e.cache});let S=u.pathname||"/",E=vt(u.searchParams),v={host:m,"x-amz-date":y,...e.headers};if(s)v["x-amz-security-token"]=s;let P=Object.keys(v).some((Ge)=>Ge.toLowerCase()==="content-type");if(r&&!P)v["content-type"]="application/x-amz-json-1.0";let N=await ht(r);if(g==="s3"&&!v["x-amz-content-sha256"])v["x-amz-content-sha256"]=N;let I=ka(v),D=$a(v),L=v["x-amz-content-sha256"]||N,O=[t,wt(S),E,I,D,L].join(`
|
|
4
|
+
`),ce=await ht(O),j=[w,y,T,ce].join(`
|
|
5
|
+
`),ae=e.cache??ke,F=await xa(i,b,h,g,j,ae),we=[`${w} Credential=${n}/${T}`,`SignedHeaders=${D}`,`Signature=${F}`].join(", ");return v.authorization=we,{url:a,method:t,headers:v,body:r||void 0}}function Wn(e){let{urlObj:t,method:a,body:r,accessKeyId:n,secretAccessKey:i,sessionToken:s,service:o,region:c,timestamp:l,date:u,credentialScope:m,algorithm:p,expiresIn:g,cache:h}=e,y=new URL(t.toString());y.searchParams.set("X-Amz-Algorithm",p),y.searchParams.set("X-Amz-Credential",`${n}/${m}`),y.searchParams.set("X-Amz-Date",l),y.searchParams.set("X-Amz-Expires",String(g));let b=o==="s3"?"UNSIGNED-PAYLOAD":Ze(r);if(o==="s3")y.searchParams.set("X-Amz-Content-Sha256",b);let T="host";if(y.searchParams.set("X-Amz-SignedHeaders",T),s)y.searchParams.set("X-Amz-Security-Token",s);let w=wt(y.pathname||"/"),S=`host:${y.hostname}
|
|
6
|
+
`,E=vt(y.searchParams),v=[a,w,E,S,T,b].join(`
|
|
7
|
+
`),P=[p,l,m,Ze(v)].join(`
|
|
8
|
+
`),N=Ma(i,u,c,o,P,h??ke);return y.searchParams.set("X-Amz-Signature",N),{url:y.toString(),method:a,headers:{},body:r||void 0}}async function Gn(e){let{urlObj:t,method:a,body:r,accessKeyId:n,secretAccessKey:i,sessionToken:s,service:o,region:c,timestamp:l,date:u,credentialScope:m,algorithm:p,expiresIn:g,cache:h}=e,y=new URL(t.toString());y.searchParams.set("X-Amz-Algorithm",p),y.searchParams.set("X-Amz-Credential",`${n}/${m}`),y.searchParams.set("X-Amz-Date",l),y.searchParams.set("X-Amz-Expires",String(g));let b=o==="s3"?"UNSIGNED-PAYLOAD":await ht(r);if(o==="s3")y.searchParams.set("X-Amz-Content-Sha256",b);let T="host";if(y.searchParams.set("X-Amz-SignedHeaders",T),s)y.searchParams.set("X-Amz-Security-Token",s);let w=wt(y.pathname||"/"),S=`host:${y.hostname}
|
|
9
|
+
`,E=vt(y.searchParams),v=[a,w,E,S,T,b].join(`
|
|
10
|
+
`),P=[p,l,m,await ht(v)].join(`
|
|
11
|
+
`),N=await xa(i,u,c,o,P,h??ke);return y.searchParams.set("X-Amz-Signature",N),{url:y.toString(),method:a,headers:{},body:r||void 0}}function Da(e){let{url:t,method:a="GET",expiresIn:r=3600,...n}=e,i=Math.min(r,604800);return K({...n,url:t,method:a,signQuery:!0,expiresIn:i}).url}async function Fn(e){let{url:t,method:a="GET",expiresIn:r=3600,...n}=e,i=Math.min(r,604800);return(await Kt({...n,url:t,method:a,signQuery:!0,expiresIn:i})).url}function ka(e){return Object.keys(e).sort().map((t)=>`${t.toLowerCase()}:${e[t].trim().replace(/\s+/g," ")}`).join(`
|
|
12
12
|
`)+`
|
|
13
|
-
`}function ka(e){return Object.keys(e).sort().map((t)=>t.toLowerCase()).join(";")}function Tt(e){let t=[];return e.forEach((a,r)=>{t.push([Bt(r),Bt(a)])}),t.sort((a,r)=>{if(a[0]<r[0])return-1;if(a[0]>r[0])return 1;if(a[1]<r[1])return-1;if(a[1]>r[1])return 1;return 0}),t.map(([a,r])=>`${a}=${r}`).join("&")}function vt(e){return e.split("/").map((t)=>Bt(t)).join("/")}function Bt(e){return encodeURIComponent(e).replace(/[!'()*]/g,(t)=>`%${t.charCodeAt(0).toString(16).toUpperCase()}`)}function Ye(e){if(!_e)throw Error("Synchronous hash not available in browser. Use signRequestAsync() instead.");return _e.createHash("sha256").update(e,"utf8").digest("hex")}function Ve(e,t){if(!_e)throw Error("Synchronous hmac not available in browser. Use signRequestAsync() instead.");return _e.createHmac("sha256",e).update(t,"utf8").digest()}async function gt(e){let t=new TextEncoder().encode(e),a=await crypto.subtle.digest("SHA-256",t);return Ma(new Uint8Array(a))}async function Fe(e,t){let a=new TextEncoder,r=typeof e==="string"?a.encode(e):e,n=a.encode(t),i=await crypto.subtle.importKey("raw",r.buffer,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",i,n.buffer);return new Uint8Array(s)}function Ma(e){return Array.from(e).map((t)=>t.toString(16).padStart(2,"0")).join("")}function La(e,t,a,r,n,i){let s=`${e}:${t}:${a}:${r}`,o=i.get(s);if(!o){let c=Ve(`AWS4${e}`,t),l=Ve(c,a),u=Ve(l,r);if(o=Ve(u,"aws4_request"),i.size>=_a){let m=i.keys().next().value;if(m)i.delete(m)}i.set(s,o)}return Ve(o,n).toString("hex")}async function xa(e,t,a,r,n,i){let s=`${e}:${t}:${a}:${r}`,o=i.get(s);if(!o){let l=await Fe(`AWS4${e}`,t),u=await Fe(l,a),m=await Fe(u,r);if(o=await Fe(m,"aws4_request"),i.size>=_a){let p=i.keys().next().value;if(p)i.delete(p)}i.set(s,o)}let c=await Fe(o,n);return Ma(c)}function Oa(e,t){return t.includes(e)}function ht(e,t,a){let r=t*Math.pow(2,e),n=Math.random()*0.3*r;return Math.min(r+n,a)}function yt(e){return new Promise((t)=>setTimeout(t,e))}async function Wa(e,t){let{maxRetries:a=3,initialDelayMs:r=100,maxDelayMs:n=5000,retryableStatusCodes:i=[429,500,502,503,504],timeoutMs:s=30000}=t??{},o,c;for(let l=0;l<=a;l++){let u=K(e),m={method:u.method,headers:u.headers};if(u.body)m.body=u.body;let p=new AbortController,g=setTimeout(()=>p.abort(),s);m.signal=p.signal;try{let h=await fetch(u.url,m);if(clearTimeout(g),c=h,h.ok)return h;if(l<a&&Oa(h.status,i)){let b=ht(l,r,n);await yt(b);continue}let y=await h.text();throw Error(`AWS API request failed (${h.status}): ${y}`)}catch(h){if(clearTimeout(g),o=h,h instanceof Error&&h.name==="AbortError")o=Error(`Request timed out after ${s}ms`);if(l<a&&!(h instanceof Error&&h.message.includes("AWS API request failed"))){let y=ht(l,r,n);await yt(y);continue}throw o}}throw o??Error("Request failed after retries")}async function Vn(e){return Wa(e,{maxRetries:0})}async function Fn(e,t){let{maxRetries:a=3,initialDelayMs:r=100,maxDelayMs:n=5000,retryableStatusCodes:i=[429,500,502,503,504],timeoutMs:s=30000}=t??{},o;for(let c=0;c<=a;c++){let l=await Kt(e),u={method:l.method,headers:l.headers};if(l.body)u.body=l.body;let m=new AbortController,p=setTimeout(()=>m.abort(),s);u.signal=m.signal;try{let g=await fetch(l.url,u);if(clearTimeout(p),g.ok)return g;if(c<a&&Oa(g.status,i)){let y=ht(c,r,n);await yt(y);continue}let h=await g.text();throw Error(`AWS API request failed (${g.status}): ${h}`)}catch(g){if(clearTimeout(p),o=g,g instanceof Error&&g.name==="AbortError")o=Error(`Request timed out after ${s}ms`);if(c<a&&!(g instanceof Error&&g.message.includes("AWS API request failed"))){let h=ht(c,r,n);await yt(h);continue}throw o}}throw o??Error("Request failed after retries")}async function jn(e){let t=await e.text(),a={},r=/<(\w+)>([^<]+)<\/\1>/g,n;while((n=r.exec(t))!==null){let[,i,s]=n;a[i]=s}return a}async function Kn(e){return await e.json()}function Hn(){De.clear()}function qn(){return De.size}function zn(){return _e!==void 0}function Jn(){return typeof crypto<"u"&&typeof crypto.subtle<"u"}var _e,De,_a=100,Ba,tt=Wn(async()=>{try{_e=await import("node:crypto")}catch{}De=new Map,Ba={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"}}),zc={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}},Jc={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}}}},Ua=".ts-cloud",$n="TS_CLOUD_STATE_DIR",Ga=null;function $c(e){Ga=e?.trim()||null}function wt(){return process.env[$n]?.trim()||Ga||Ua}function Yn(...e){return ft(wt(),...e)}function Xn(e,...t){let a=wt();return Ut(a)?ft(a,...t):ft(e,a,...t)}function Yc(e,t=process.cwd()){let a=(n,i)=>{let s=Qn(n,i);return s===""||!s.startsWith("..")&&!Ut(s)},r=Ut(e)?e:ft(t,e);return a(Xn(t),r)}function Va(e){let t=e.infrastructure?.compute!=null,a=Object.values(e.environments??{}).some((r)=>r?.app!=null);return{server:t,serverless:a}}function Xc(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:t}=Va(e);return t?"serverless":"server"}function Zc(e){let{server:t,serverless:a}=Va(e);if(t&&a)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"&&a&&!t)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&t&&!a)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function el(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function Zn(e){return typeof e==="object"&&e!==null?e:{}}function ei(e){return e===!0||typeof e==="object"&&e!==null}function ti(e,t){let a=t?e.environments?.[t]:void 0;if(a?.domain)return a.domain;let r=Object.values(e.sites??{}),n=e.sites?.main?.domain??r.find((i)=>i.domain)?.domain;if(n)return n;return`${e.project?.slug??"app"}.local`}function ai(e){let t=e.indexOf(".");return t>0?e.slice(t+1):void 0}function tl(e,t={}){let a=e.infrastructure?.compute?.managedServices?.mail,r=Zn(a),n=t.environmentType??(t.environment?e.environments?.[t.environment]?.type:void 0),i=r.mode??(n==="production"?"server":"catcher"),s=i==="server",o=ti(e,t.environment),c=r.hostname??(s?`mail.${o}`:"localhost"),l=r.ports??{},u=s?{smtp:l.smtp??25,submission:l.submission??587,submissions:l.submissions??465,imap:l.imap??143,imaps:l.imaps??993,webmail:l.webmail??8080,managesieve:l.managesieve}:{smtp:l.smtp??1025,submission:l.submission,submissions:l.submissions,imap:l.imap,imaps:l.imaps,webmail:l.webmail??8025,managesieve:l.managesieve},m=r.tls??{},p=m.enabled??s,g=!!(m.certPath&&m.keyPath),h=(r.accounts??[]).map((I)=>({address:I.address,password:I.password})),y=typeof r.dkim==="object"&&r.dkim!==null?r.dkim:{},b=r.dkim===!1?!1:r.dkim===!0||s,T=typeof r.webmail==="object"&&r.webmail!==null?r.webmail:{},w=r.webmail===!1?!1:T.enabled??!0,S=r.spam??{},E=r.delivery??(s?"direct":"none"),v=r.expose??s,P=ai(c),N=[...new Set([c,...P?[P]:[],...r.domains??[]])];return{enabled:ei(a),mode:i,version:r.version,hostname:c,domains:N,ports:u,tls:{enabled:p,acme:p&&!g&&(m.acme??!0),certPath:m.certPath,keyPath:m.keyPath,requireForAuth:m.requireForAuth??(p&&s),acmeEmail:m.acmeEmail??h[0]?.address},dkim:{enabled:b,selector:y.selector??"default",rotate:y.rotate??!1,rotateIntervalDays:y.rotateIntervalDays??90},webmail:{enabled:w,port:T.port??u.webmail,domain:T.domain},delivery:E,sesRegion:r.sesRegion??"us-east-1",accounts:h,storagePath:r.storagePath??"/var/lib/mail",maxMessageSize:r.maxMessageSize??26214400,spam:{enabled:S.enabled??s,enforce:S.enforce??!1,junkScore:S.junkScore??5,rejectScore:S.rejectScore??12,dnsbl:S.dnsbl??s,greylist:S.greylist??!1},webhookUrl:r.webhookUrl,expose:v,bindAddress:v?"0.0.0.0":"127.0.0.1"}}function al(e){if(!e.enabled||!e.expose)return[];let t=[e.ports.smtp,e.ports.submission,e.ports.submissions,e.ports.imap,e.ports.imaps,e.ports.managesieve].filter((a)=>typeof a==="number");if(e.webmail.enabled&&!e.webmail.domain)t.push(e.webmail.port);return[...new Set(t)].sort((a,r)=>a-r)}function rl(e){if(!e.enabled)return{};let t=e.ports.submission??e.ports.smtp,a={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(t)};if(e.mode==="server"){a.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let r=e.accounts[0];if(r)a.MAIL_USERNAME=r.address,a.MAIL_PASSWORD=r.password}else a.MAIL_ENCRYPTION="null",a.MAIL_USERNAME="null",a.MAIL_PASSWORD="null";return a}function nl(e){if(e.cloud?.provider)return e.cloud.provider;if(e.hetzner?.apiToken)return"hetzner";return"aws"}class ri{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,t){return this.template.Resources[e]=t,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,t){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=t,this}addOutput(e,t){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=t,this}hasResource(e){return e in this.template.Resources}getResources(){return this.template.Resources}build(){return this.template}toJSON(e=!0){return JSON.stringify(this.template,null,e?2:0)}toYAML(){return this.convertToYAML(this.template)}convertToYAML(e,t=0){let a=" ".repeat(t),r="";for(let[n,i]of Object.entries(e)){if(i===null||i===void 0)continue;if(typeof i==="object"&&!Array.isArray(i))r+=`${a}${n}:
|
|
13
|
+
`}function $a(e){return Object.keys(e).sort().map((t)=>t.toLowerCase()).join(";")}function vt(e){let t=[];return e.forEach((a,r)=>{t.push([Wt(r),Wt(a)])}),t.sort((a,r)=>{if(a[0]<r[0])return-1;if(a[0]>r[0])return 1;if(a[1]<r[1])return-1;if(a[1]>r[1])return 1;return 0}),t.map(([a,r])=>`${a}=${r}`).join("&")}function wt(e){return e.split("/").map((t)=>Wt(t)).join("/")}function Wt(e){return encodeURIComponent(e).replace(/[!'()*]/g,(t)=>`%${t.charCodeAt(0).toString(16).toUpperCase()}`)}function Ze(e){if(!_e)throw Error("Synchronous hash not available in browser. Use signRequestAsync() instead.");return _e.createHash("sha256").update(e,"utf8").digest("hex")}function Ve(e,t){if(!_e)throw Error("Synchronous hmac not available in browser. Use signRequestAsync() instead.");return _e.createHmac("sha256",e).update(t,"utf8").digest()}async function ht(e){let t=new TextEncoder().encode(e),a=await crypto.subtle.digest("SHA-256",t);return La(new Uint8Array(a))}async function Ue(e,t){let a=new TextEncoder,r=typeof e==="string"?a.encode(e):e,n=a.encode(t),i=await crypto.subtle.importKey("raw",r.buffer,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),s=await crypto.subtle.sign("HMAC",i,n.buffer);return new Uint8Array(s)}function La(e){return Array.from(e).map((t)=>t.toString(16).padStart(2,"0")).join("")}function Ma(e,t,a,r,n,i){let s=`${e}:${t}:${a}:${r}`,o=i.get(s);if(!o){let c=Ve(`AWS4${e}`,t),l=Ve(c,a),u=Ve(l,r);if(o=Ve(u,"aws4_request"),i.size>=_a){let m=i.keys().next().value;if(m)i.delete(m)}i.set(s,o)}return Ve(o,n).toString("hex")}async function xa(e,t,a,r,n,i){let s=`${e}:${t}:${a}:${r}`,o=i.get(s);if(!o){let l=await Ue(`AWS4${e}`,t),u=await Ue(l,a),m=await Ue(u,r);if(o=await Ue(m,"aws4_request"),i.size>=_a){let p=i.keys().next().value;if(p)i.delete(p)}i.set(s,o)}let c=await Ue(o,n);return La(c)}function Oa(e,t){return t.includes(e)}function yt(e,t,a){let r=t*Math.pow(2,e),n=Math.random()*0.3*r;return Math.min(r+n,a)}function ft(e){return new Promise((t)=>setTimeout(t,e))}async function Ba(e,t){let{maxRetries:a=3,initialDelayMs:r=100,maxDelayMs:n=5000,retryableStatusCodes:i=[429,500,502,503,504],timeoutMs:s=30000}=t??{},o,c;for(let l=0;l<=a;l++){let u=K(e),m={method:u.method,headers:u.headers};if(u.body)m.body=u.body;let p=new AbortController,g=setTimeout(()=>p.abort(),s);m.signal=p.signal;try{let h=await fetch(u.url,m);if(clearTimeout(g),c=h,h.ok)return h;if(l<a&&Oa(h.status,i)){let b=yt(l,r,n);await ft(b);continue}let y=await h.text();throw Error(`AWS API request failed (${h.status}): ${y}`)}catch(h){if(clearTimeout(g),o=h,h instanceof Error&&h.name==="AbortError")o=Error(`Request timed out after ${s}ms`);if(l<a&&!(h instanceof Error&&h.message.includes("AWS API request failed"))){let y=yt(l,r,n);await ft(y);continue}throw o}}throw o??Error("Request failed after retries")}async function Vn(e){return Ba(e,{maxRetries:0})}async function Un(e,t){let{maxRetries:a=3,initialDelayMs:r=100,maxDelayMs:n=5000,retryableStatusCodes:i=[429,500,502,503,504],timeoutMs:s=30000}=t??{},o;for(let c=0;c<=a;c++){let l=await Kt(e),u={method:l.method,headers:l.headers};if(l.body)u.body=l.body;let m=new AbortController,p=setTimeout(()=>m.abort(),s);u.signal=m.signal;try{let g=await fetch(l.url,u);if(clearTimeout(p),g.ok)return g;if(c<a&&Oa(g.status,i)){let y=yt(c,r,n);await ft(y);continue}let h=await g.text();throw Error(`AWS API request failed (${g.status}): ${h}`)}catch(g){if(clearTimeout(p),o=g,g instanceof Error&&g.name==="AbortError")o=Error(`Request timed out after ${s}ms`);if(c<a&&!(g instanceof Error&&g.message.includes("AWS API request failed"))){let h=yt(c,r,n);await ft(h);continue}throw o}}throw o??Error("Request failed after retries")}async function jn(e){let t=await e.text(),a={},r=/<(\w+)>([^<]+)<\/\1>/g,n;while((n=r.exec(t))!==null){let[,i,s]=n;a[i]=s}return a}async function Kn(e){return await e.json()}function Hn(){ke.clear()}function qn(){return ke.size}function zn(){return _e!==void 0}function Qn(){return typeof crypto<"u"&&typeof crypto.subtle<"u"}var _e,ke,_a=100,Wa,at=Bn(async()=>{try{_e=await import("node:crypto")}catch{}ke=new Map,Wa={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"}}),zc={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}},Qc={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}}}},Ga=".ts-cloud",Yn="TS_CLOUD_STATE_DIR",Fa=null;function Yc(e){Fa=e?.trim()||null}function Et(){return process.env[Yn]?.trim()||Fa||Ga}function Zn(...e){return St(Et(),...e)}function Xn(e,...t){let a=Et();return Gt(a)?St(a,...t):St(e,a,...t)}function Zc(e,t=process.cwd()){let a=(n,i)=>{let s=Jn(n,i);return s===""||!s.startsWith("..")&&!Gt(s)},r=Gt(e)?e:St(t,e);return a(Xn(t),r)}function Va(e){let t=e.infrastructure?.compute!=null,a=Object.values(e.environments??{}).some((r)=>r?.app!=null);return{server:t,serverless:a}}function Xc(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:t}=Va(e);return t?"serverless":"server"}function el(e){let{server:t,serverless:a}=Va(e);if(t&&a)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"&&a&&!t)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&t&&!a)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function tl(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function ei(e){return typeof e==="object"&&e!==null?e:{}}function ti(e){return e===!0||typeof e==="object"&&e!==null}function ai(e,t){let a=t?e.environments?.[t]:void 0;if(a?.domain)return a.domain;let r=Object.values(e.sites??{}),n=e.sites?.main?.domain??r.find((i)=>i.domain)?.domain;if(n)return n;return`${e.project?.slug??"app"}.local`}function ri(e){let t=e.indexOf(".");return t>0?e.slice(t+1):void 0}function al(e,t={}){let a=e.infrastructure?.compute?.managedServices?.mail,r=ei(a),n=t.environmentType??(t.environment?e.environments?.[t.environment]?.type:void 0),i=r.mode??(n==="production"?"server":"catcher"),s=i==="server",o=ai(e,t.environment),c=r.hostname??(s?`mail.${o}`:"localhost"),l=r.ports??{},u=s?{smtp:l.smtp??25,submission:l.submission??587,submissions:l.submissions??465,imap:l.imap??143,imaps:l.imaps??993,webmail:l.webmail??8080,managesieve:l.managesieve}:{smtp:l.smtp??1025,submission:l.submission,submissions:l.submissions,imap:l.imap,imaps:l.imaps,webmail:l.webmail??8025,managesieve:l.managesieve},m=r.tls??{},p=m.enabled??s,g=!!(m.certPath&&m.keyPath),h=(r.accounts??[]).map((I)=>({address:I.address,password:I.password})),y=typeof r.dkim==="object"&&r.dkim!==null?r.dkim:{},b=r.dkim===!1?!1:r.dkim===!0||s,T=typeof r.webmail==="object"&&r.webmail!==null?r.webmail:{},w=r.webmail===!1?!1:T.enabled??!0,S=r.spam??{},E=r.delivery??(s?"direct":"none"),v=r.expose??s,P=ri(c),N=[...new Set([c,...P?[P]:[],...r.domains??[]])];return{enabled:ti(a),mode:i,version:r.version,hostname:c,domains:N,ports:u,tls:{enabled:p,acme:p&&!g&&(m.acme??!0),certPath:m.certPath,keyPath:m.keyPath,requireForAuth:m.requireForAuth??(p&&s),acmeEmail:m.acmeEmail??h[0]?.address},dkim:{enabled:b,selector:y.selector??"default",rotate:y.rotate??!1,rotateIntervalDays:y.rotateIntervalDays??90},webmail:{enabled:w,port:T.port??u.webmail,domain:T.domain},delivery:E,sesRegion:r.sesRegion??"us-east-1",accounts:h,storagePath:r.storagePath??"/var/lib/mail",maxMessageSize:r.maxMessageSize??26214400,spam:{enabled:S.enabled??s,enforce:S.enforce??!1,junkScore:S.junkScore??5,rejectScore:S.rejectScore??12,dnsbl:S.dnsbl??s,greylist:S.greylist??!1},webhookUrl:r.webhookUrl,expose:v,bindAddress:v?"0.0.0.0":"127.0.0.1"}}function rl(e){if(!e.enabled||!e.expose)return[];let t=[e.ports.smtp,e.ports.submission,e.ports.submissions,e.ports.imap,e.ports.imaps,e.ports.managesieve].filter((a)=>typeof a==="number");if(e.webmail.enabled&&!e.webmail.domain)t.push(e.webmail.port);return[...new Set(t)].sort((a,r)=>a-r)}function nl(e){if(!e.enabled)return{};let t=e.ports.submission??e.ports.smtp,a={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(t)};if(e.mode==="server"){a.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let r=e.accounts[0];if(r)a.MAIL_USERNAME=r.address,a.MAIL_PASSWORD=r.password}else a.MAIL_ENCRYPTION="null",a.MAIL_USERNAME="null",a.MAIL_PASSWORD="null";return a}function il(e){if(e.cloud?.provider)return e.cloud.provider;if(e.hetzner?.apiToken)return"hetzner";return"aws"}class ni{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,t){return this.template.Resources[e]=t,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,t){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=t,this}addOutput(e,t){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=t,this}hasResource(e){return e in this.template.Resources}getResources(){return this.template.Resources}build(){return this.template}toJSON(e=!0){return JSON.stringify(this.template,null,e?2:0)}toYAML(){return this.convertToYAML(this.template)}convertToYAML(e,t=0){let a=" ".repeat(t),r="";for(let[n,i]of Object.entries(e)){if(i===null||i===void 0)continue;if(typeof i==="object"&&!Array.isArray(i))r+=`${a}${n}:
|
|
14
14
|
${this.convertToYAML(i,t+1)}`;else if(Array.isArray(i)){r+=`${a}${n}:
|
|
15
15
|
`;for(let s of i)if(typeof s==="object")r+=`${a} -
|
|
16
16
|
${this.convertToYAML(s,t+2)}`;else r+=`${a} - ${s}
|
|
17
17
|
`}else r+=`${a}${n}: ${i}
|
|
18
|
-
`}return r}}var C={Ref:(e)=>({Ref:e}),GetAtt:(e,t)=>({"Fn::GetAtt":[e,t]}),Sub:(e,t)=>{if(t)return{"Fn::Sub":[e,t]};return{"Fn::Sub":e}},Join:(e,t)=>({"Fn::Join":[e,t]}),Select:(e,t)=>({"Fn::Select":[e,t]}),Split:(e,t)=>({"Fn::Split":[e,t]}),GetAZs:(e="")=>({"Fn::GetAZs":e}),ImportValue:(e)=>({"Fn::ImportValue":e}),If:(e,t,a)=>({"Fn::If":[e,t,a]}),Equals:(e,t)=>({"Fn::Equals":[e,t]}),And:(...e)=>({"Fn::And":e}),Or:(...e)=>({"Fn::Or":e}),Not:(e)=>({"Fn::Not":[e]}),Base64:(e)=>({"Fn::Base64":e})},
|
|
18
|
+
`}return r}}var C={Ref:(e)=>({Ref:e}),GetAtt:(e,t)=>({"Fn::GetAtt":[e,t]}),Sub:(e,t)=>{if(t)return{"Fn::Sub":[e,t]};return{"Fn::Sub":e}},Join:(e,t)=>({"Fn::Join":[e,t]}),Select:(e,t)=>({"Fn::Select":[e,t]}),Split:(e,t)=>({"Fn::Split":[e,t]}),GetAZs:(e="")=>({"Fn::GetAZs":e}),ImportValue:(e)=>({"Fn::ImportValue":e}),If:(e,t,a)=>({"Fn::If":[e,t,a]}),Equals:(e,t)=>({"Fn::Equals":[e,t]}),And:(...e)=>({"Fn::And":e}),Or:(...e)=>({"Fn::Or":e}),Not:(e)=>({"Fn::Not":[e]}),Base64:(e)=>({"Fn::Base64":e})},sl={AccountId:{Ref:"AWS::AccountId"},Region:{Ref:"AWS::Region"},StackId:{Ref:"AWS::StackId"},StackName:{Ref:"AWS::StackName"},NotificationARNs:{Ref:"AWS::NotificationARNs"},Partition:{Ref:"AWS::Partition"},URLSuffix:{Ref:"AWS::URLSuffix"},NoValue:{Ref:"AWS::NoValue"}};function A(e){let{slug:t,environment:a,resourceType:r,timestamp:n,suffix:i}=e,s=[t,a,r];if(n)s.push(n);if(i)s.push(i);return s.join("-")}function f(e){return e.split("-").map((t)=>t.charAt(0).toUpperCase()+t.slice(1)).join("")}function ol(){return Date.now().toString()}function cl(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function ll(e,t){return e.project.stackName??`${e.project.slug}-${t}`}function ul(e,t,a,r){return a.stackName??`${e.project.slug}-${r}-${t}-site`}function dl(e,t){return`${e.project.slug}-${t}`}function ml(e,t,a,r){if(r)return r;if(a==="main")return`${e}-${t}-site`;return`${e}-${t}-${a}`}function pl(e,t,a,r){return r??`${e}-${t}-${a}`}function gl(e,t){return`${e}-${t}-deploy`}function hl(e,t){return`${e.project.slug}-${t}-app`}function yl(e,t){return`${e}-${t}-deployments`}function ii(e,t){return`${e}-${t}-assets`}class si{nodes=new Map;addResource(e,t){let a=this.extractDependencies(t);this.nodes.set(e,{logicalId:e,resource:t,dependencies:a})}extractDependencies(e){let t=new Set;if(e.DependsOn)if(Array.isArray(e.DependsOn))e.DependsOn.forEach((a)=>t.add(a));else t.add(e.DependsOn);return this.findReferences(e.Properties||{},t),t}findReferences(e,t){if(!e||typeof e!=="object")return;if("Ref"in e&&typeof e.Ref==="string"){if(!e.Ref.startsWith("AWS::"))t.add(e.Ref)}if("Fn::GetAtt"in e&&Array.isArray(e["Fn::GetAtt"]))t.add(e["Fn::GetAtt"][0]);for(let a of Object.values(e))if(typeof a==="object")this.findReferences(a,t)}topologicalSort(){let e=[],t=new Set,a=new Set,r=(n)=>{if(t.has(n))return;if(a.has(n))throw Error(`Circular dependency detected: ${n}`);a.add(n);let i=this.nodes.get(n);if(i)for(let s of i.dependencies)r(s);a.delete(n),t.add(n),e.push(n)};for(let n of this.nodes.keys())r(n);return e}validate(){for(let[e,t]of this.nodes.entries())for(let a of t.dependencies)if(!this.nodes.has(a))throw Error(`Resource "${e}" depends on "${a}" which does not exist`)}getDependents(e){let t=[];for(let[a,r]of this.nodes.entries())if(r.dependencies.has(e))t.push(a);return t}}function fl(e,t){let a=[],r=[],n=[],i=[],s=[],o=e.Resources||{},c=t.Resources||{},l=new Set([...Object.keys(o),...Object.keys(c)]);for(let m of l){let p=o[m],g=c[m];if(!p&&g)a.push({logicalId:m,action:"add",resourceType:g.Type});else if(p&&!g)r.push({logicalId:m,action:"remove",resourceType:p.Type});else if(p&&g)if(p.Type!==g.Type)i.push({logicalId:m,action:"replace",resourceType:g.Type,reason:`Type changed from ${p.Type} to ${g.Type}`});else{let h=Ua(p.Properties||{},g.Properties||{});if(h.length>0)if(oi(p.Type,h))i.push({logicalId:m,action:"replace",resourceType:g.Type,changes:h,reason:"Property changes require replacement"});else n.push({logicalId:m,action:"update",resourceType:g.Type,changes:h});else s.push(m)}}let u=ci([...r,...i,...n]);return{added:a,removed:r,updated:n,replaced:i,unchanged:s,summary:{totalChanges:a.length+r.length+n.length+i.length,requiresReplacement:i.length>0,dangerousChanges:u}}}function Ua(e,t,a=""){let r=[],n=new Set([...Object.keys(e),...Object.keys(t)]);for(let i of n){let s=a?`${a}.${i}`:i,o=e[i],c=t[i];if(o===void 0&&c!==void 0)r.push({path:s,oldValue:void 0,newValue:c});else if(o!==void 0&&c===void 0)r.push({path:s,oldValue:o,newValue:void 0});else if(typeof o!==typeof c)r.push({path:s,oldValue:o,newValue:c});else if(typeof o==="object"&&o!==null)if(Array.isArray(o)&&Array.isArray(c)){if(JSON.stringify(o)!==JSON.stringify(c))r.push({path:s,oldValue:o,newValue:c})}else if(!Array.isArray(o)&&!Array.isArray(c)){let l=Ua(o,c,s);r.push(...l)}else r.push({path:s,oldValue:o,newValue:c});else if(o!==c)r.push({path:s,oldValue:o,newValue:c})}return r}function oi(e,t){let a={"AWS::S3::Bucket":new Set(["BucketName"]),"AWS::DynamoDB::Table":new Set(["TableName","KeySchema"]),"AWS::RDS::DBInstance":new Set(["DBInstanceIdentifier","DBName","Engine"]),"AWS::Lambda::Function":new Set(["FunctionName"]),"AWS::EC2::Instance":new Set(["ImageId","InstanceType","KeyName"]),"AWS::ECS::TaskDefinition":new Set(["Family","ContainerDefinitions"]),"AWS::ElastiCache::CacheCluster":new Set(["CacheNodeType","Engine"]),"AWS::CloudFront::Distribution":new Set([]),"AWS::Route53::HostedZone":new Set(["Name"]),"AWS::IAM::Role":new Set(["RoleName","Path"]),"AWS::KMS::Key":new Set(["KeyPolicy"]),"AWS::Cognito::UserPool":new Set(["UserPoolName"]),"AWS::OpenSearchService::Domain":new Set(["DomainName"])}[e];if(!a)return!1;for(let r of t){let n=r.path.split(".")[0];if(a.has(n))return!0}return!1}function ci(e){let t=[];for(let a of e){if(a.action==="remove"&&(a.resourceType==="AWS::RDS::DBInstance"||a.resourceType==="AWS::DynamoDB::Table"||a.resourceType==="AWS::ElastiCache::CacheCluster"))t.push(`Removing ${a.resourceType} ${a.logicalId} - data loss risk!`);if(a.action==="replace"&&(a.resourceType==="AWS::RDS::DBInstance"||a.resourceType==="AWS::DynamoDB::Table"))t.push(`Replacing ${a.resourceType} ${a.logicalId} - data loss risk!`);if((a.action==="remove"||a.action==="replace")&&a.resourceType==="AWS::S3::Bucket")t.push(`${a.action==="remove"?"Removing":"Replacing"} S3 bucket ${a.logicalId} - data loss risk!`);if(a.action==="replace"&&a.resourceType==="AWS::EC2::Instance")t.push(`Replacing EC2 instance ${a.logicalId} - downtime expected`);if(a.action==="update"&&a.resourceType==="AWS::EC2::SecurityGroup")t.push(`Updating security group ${a.logicalId} - may affect connectivity`);if((a.action==="update"||a.action==="replace")&&(a.resourceType==="AWS::IAM::Role"||a.resourceType==="AWS::IAM::Policy"))t.push(`Modifying IAM ${a.resourceType.split("::")[2]} ${a.logicalId} - may affect permissions`)}return t}function Sl(e){let t=[];if(t.push(`=== Stack Update Analysis ===
|
|
19
19
|
`),e.summary.totalChanges===0)return t.push(`No changes detected.
|
|
20
20
|
`),t.join(`
|
|
21
21
|
`);if(t.push(`Total changes: ${e.summary.totalChanges}`),t.push(`Requires replacement: ${e.summary.requiresReplacement?"Yes":"No"}
|
|
22
22
|
`),e.summary.dangerousChanges.length>0){t.push("⚠️ DANGEROUS CHANGES DETECTED:");for(let a of e.summary.dangerousChanges)t.push(` • ${a}`);t.push("")}if(e.added.length>0){t.push(`✅ Resources to Add (${e.added.length}):`);for(let a of e.added)t.push(` + ${a.logicalId} (${a.resourceType})`);t.push("")}if(e.removed.length>0){t.push(`❌ Resources to Remove (${e.removed.length}):`);for(let a of e.removed)t.push(` - ${a.logicalId} (${a.resourceType})`);t.push("")}if(e.replaced.length>0){t.push(`\uD83D\uDD04 Resources to Replace (${e.replaced.length}):`);for(let a of e.replaced){if(t.push(` ~ ${a.logicalId} (${a.resourceType})`),a.reason)t.push(` Reason: ${a.reason}`);if(a.changes){for(let r of a.changes.slice(0,3))t.push(` • ${r.path}: ${JSON.stringify(r.oldValue)} → ${JSON.stringify(r.newValue)}`);if(a.changes.length>3)t.push(` ... and ${a.changes.length-3} more changes`)}}t.push("")}if(e.updated.length>0){t.push(`\uD83D\uDCDD Resources to Update (${e.updated.length}):`);for(let a of e.updated)if(t.push(` ~ ${a.logicalId} (${a.resourceType})`),a.changes){for(let r of a.changes.slice(0,3))t.push(` • ${r.path}: ${JSON.stringify(r.oldValue)} → ${JSON.stringify(r.newValue)}`);if(a.changes.length>3)t.push(` ... and ${a.changes.length-3} more changes`)}t.push("")}if(e.unchanged.length>0)t.push(`⚪ Unchanged Resources (${e.unchanged.length})`);return t.join(`
|
|
23
|
-
`)}class Ee{static createBucket(e){let{name:t,bucketName:a,slug:r,environment:n,public:i=!1,versioning:s=!1,website:o=!1,encryption:c=!0,intelligentTiering:l=!1,cors:u,lifecycleRules:m}=e,p=a??A({slug:r,environment:n,resourceType:"s3",suffix:t}),g=f(p),h={Type:"AWS::S3::Bucket",Properties:{BucketName:p}};if(c)h.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(s)h.Properties.VersioningConfiguration={Status:"Enabled"};if(o)h.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!i)h.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(u&&u.length>0)h.Properties.CorsConfiguration={CorsRules:u.map((b)=>({AllowedOrigins:b.allowedOrigins,AllowedMethods:b.allowedMethods,AllowedHeaders:b.allowedHeaders,MaxAge:b.maxAge}))};if(m&&m.length>0)h.Properties.LifecycleConfiguration={Rules:m.map((b)=>({Id:b.id,Status:b.enabled?"Enabled":"Disabled",ExpirationInDays:b.expirationDays,Transitions:b.transitions?.map((T)=>({TransitionInDays:T.days,StorageClass:T.storageClass}))}))};if(l&&m){let b={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!h.Properties.LifecycleConfiguration)h.Properties.LifecycleConfiguration={Rules:[]};h.Properties.LifecycleConfiguration.Rules.push({Id:b.id,Status:"Enabled",Transitions:b.transitions?.map((T)=>({TransitionInDays:T.days,StorageClass:T.storageClass}))})}let y;if(i)y={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:C.Ref(g),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[C.Join("",[C.GetAtt(g,"Arn"),"/*"])]}]}}};return{bucket:h,bucketPolicy:y,logicalId:g}}static enableVersioning(e){if(!e.Properties)e.Properties={};return e.Properties.VersioningConfiguration={Status:"Enabled"},e}static enableWebsiteHosting(e,t="index.html",a="error.html"){if(!e.Properties)e.Properties={};return e.Properties.WebsiteConfiguration={IndexDocument:t,ErrorDocument:a},e}static setLifecycleRules(e,t){if(!e.Properties)e.Properties={};return e.Properties.LifecycleConfiguration={Rules:t.map((a)=>({Id:a.id,Status:a.enabled?"Enabled":"Disabled",ExpirationInDays:a.expirationDays,Transitions:a.transitions?.map((r)=>({TransitionInDays:r.days,StorageClass:r.storageClass}))}))},e}static enableIntelligentTiering(e){if(!e.Properties)e.Properties={};if(!e.Properties.LifecycleConfiguration)e.Properties.LifecycleConfiguration={Rules:[]};return e.Properties.LifecycleConfiguration.Rules.push({Id:"IntelligentTieringRule",Status:"Enabled",Transitions:[{TransitionInDays:0,StorageClass:"INTELLIGENT_TIERING"}]}),e}static addLambdaNotification(e,t){if(!e.Properties)e.Properties={};if(!e.Properties.NotificationConfiguration)e.Properties.NotificationConfiguration={};if(!e.Properties.NotificationConfiguration.LambdaConfigurations)e.Properties.NotificationConfiguration.LambdaConfigurations=[];let a={Event:t.events[0],Function:t.functionArn};if(t.filter)a.Filter={S3Key:{Rules:[...t.filter.prefix?[{Name:"prefix",Value:t.filter.prefix}]:[],...t.filter.suffix?[{Name:"suffix",Value:t.filter.suffix}]:[]]}};for(let r of t.events){let n={...a,Event:r};e.Properties.NotificationConfiguration.LambdaConfigurations.push(n)}return e}static Notifications={onObjectCreated:(e)=>({functionArn:e,events:["s3:ObjectCreated:*"]}),onObjectRemoved:(e)=>({functionArn:e,events:["s3:ObjectRemoved:*"]}),onImageUpload:(e,t)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:t,suffix:".jpg"}}),onFileType:(e,t,a)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:a,suffix:t}}),onFolderUpload:(e,t)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:t.endsWith("/")?t:`${t}/`}})};static createBackupPlan(e){let{name:t,slug:a,environment:r,bucketLogicalIds:n,retentionDays:i,schedule:s="cron(0 5 * * ? *)",vaultName:o,enableContinuousBackup:c=!1,moveToColdStorageAfterDays:l}=e,u=o||A({slug:a,environment:r,resourceType:"backup-vault",suffix:t}),m=f(u),p={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:u}},g=A({slug:a,environment:r,resourceType:"backup-role",suffix:t}),h=f(g),y={Type:"AWS::IAM::Role",Properties:{RoleName:g,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"backup.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup","arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"]}},b=A({slug:a,environment:r,resourceType:"backup-plan",suffix:t}),T=f(b),w={DeleteAfterDays:i};if(l&&l<i)w.MoveToColdStorageAfterDays=l;let S={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:b,BackupPlanRule:[{RuleName:`${t}-daily-backup`,TargetBackupVault:C.Ref(m),ScheduleExpression:s,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:w,EnableContinuousBackup:c}]}}},E=A({slug:a,environment:r,resourceType:"backup-selection",suffix:t}),v=f(E),P=n.map((I)=>C.GetAtt(I,"Arn")),N={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:C.Ref(T),BackupSelection:{SelectionName:E,IamRoleArn:C.GetAtt(h,"Arn"),Resources:P}}};return{vault:p,plan:S,selection:N,role:y,vaultLogicalId:m,planLogicalId:T,selectionLogicalId:v,roleLogicalId:h}}static BackupSchedules={HOURLY:"cron(0 * * * ? *)",DAILY_5AM:"cron(0 5 * * ? *)",DAILY_MIDNIGHT:"cron(0 0 * * ? *)",WEEKLY_SUNDAY:"cron(0 5 ? * SUN *)",WEEKLY_SATURDAY:"cron(0 5 ? * SAT *)",MONTHLY_FIRST:"cron(0 5 1 * ? *)",EVERY_12_HOURS:"cron(0 */12 * * ? *)",EVERY_6_HOURS:"cron(0 */6 * * ? *)"};static BackupRetention={ONE_DAY:1,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,THREE_MONTHS:90,SIX_MONTHS:180,ONE_YEAR:365,TWO_YEARS:730,FIVE_YEARS:1825,SEVEN_YEARS:2555};static createWwwRedirectBucket(e){let{slug:t,environment:a,sourceDomain:r,targetDomain:n,protocol:i="https"}=e,s=A({slug:t,environment:a,resourceType:"s3",suffix:"www-redirect"}),o=f(s),c={Type:"AWS::S3::Bucket",Properties:{BucketName:r,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:n,Protocol:i}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},l={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:C.Ref(o),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[C.Join("",[C.GetAtt(o,"Arn"),"/*"])]}]}}};return{bucket:c,bucketPolicy:l,logicalId:o}}static createDocsBucket(e){let{slug:t,environment:a,domain:r}=e,n=r||A({slug:t,environment:a,resourceType:"s3",suffix:"docs"}),i=f(n);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:n,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:i}}static createEmailBucket(e){let{slug:t,environment:a}=e,r=A({slug:t,environment:a,resourceType:"s3",suffix:"email"}),n=f(r),i={Type:"AWS::S3::Bucket",Properties:{BucketName:r,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"EmailRetention",Status:"Enabled",ExpirationInDays:90,Transitions:[{TransitionInDays:30,StorageClass:"STANDARD_IA"}]}]}}},s={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:C.Ref(n),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:C.Join("",[C.GetAtt(n,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":C.Ref("AWS::AccountId")}}}]}}};return{bucket:i,bucketPolicy:s,logicalId:n}}static docsExist(e={}){let{projectRoot:t=process.cwd(),docsPaths:a=["docs","documentation","doc"]}=e;for(let r of a){let n=be(t,r);if(je(n)){let i=["dist","build",".bunpress/dist","_site","out","public"];for(let s of i){let o=be(n,s);if(je(o))try{if(ci(o).length>0)return{exists:!0,path:n,hasDistFolder:!0,distPath:o}}catch{}}return{exists:!0,path:n,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(e){let t=Ee.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!t.exists)return{bucket:null,logicalId:null,docsInfo:t};let a=Ee.createDocsBucket({slug:e.slug,environment:e.environment,domain:e.domain});return{bucket:a.bucket,bucketPolicy:a.bucketPolicy,logicalId:a.logicalId,docsInfo:t}}static createPrivateBucket(e){let{slug:t,environment:a,enableVersioning:r=!0,retentionDays:n,encryptionKeyArn:i}=e,s=A({slug:t,environment:a,resourceType:"s3",suffix:"private"}),o=f(s);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:s,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:i?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:i}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:r?{Status:"Enabled"}:void 0,LifecycleConfiguration:n?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:n}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:o}}static checkSourcePaths(e={}){let{projectRoot:t=process.cwd(),paths:a={}}=e,r=a.web||"views/web/dist",n=a.docs||"docs/dist",i=a.private||"private";return{web:{exists:je(be(t,r)),path:be(t,r)},docs:{exists:je(be(t,n)),path:be(t,n)},private:{exists:je(be(t,i)),path:be(t,i)}}}static createDeploymentBuckets(e){let{slug:t,environment:a,domain:r,projectRoot:n,paths:i}=e,s=Ee.checkSourcePaths({projectRoot:n,paths:i}),o={},c={web:!1,docs:!1,private:!1},l=Ee.createBucket({name:"web",slug:t,environment:a,public:!1,versioning:!1,encryption:!0});if(o[l.logicalId]=l.bucket,c.web=!0,s.docs.exists){let u=Ee.createDocsBucket({slug:t,environment:a,domain:r?`docs.${r}`:void 0});if(o[u.logicalId]=u.bucket,u.bucketPolicy)o[`${u.logicalId}Policy`]=u.bucketPolicy;c.docs=!0}if(s.private.exists){let u=Ee.createPrivateBucket({slug:t,environment:a,enableVersioning:!0});o[u.logicalId]=u.bucket,c.private=!0}return{resources:o,created:c,sourcePaths:s}}}class me{static createRepository(e){let{name:t,slug:a,environment:r,scanOnPush:n=!0,imageMutability:i="MUTABLE",encryption:s="AES256",kmsKey:o,lifecyclePolicy:c,tags:l}=e,u=A({slug:a,environment:r,resourceType:"ecr",suffix:t}),m=f(u),p={Type:"AWS::ECR::Repository",Properties:{RepositoryName:u,ImageTagMutability:i,ImageScanningConfiguration:{ScanOnPush:n},EncryptionConfiguration:{EncryptionType:s,...o&&s==="KMS"?{KmsKey:o}:{}}}};if(c)p.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(me.generateLifecyclePolicy(c))};if(l)p.Properties.Tags=Object.entries(l).map(([g,h])=>({Key:g,Value:h}));return{repository:p,logicalId:m}}static generateLifecyclePolicy(e){let t=[];if(e.untaggedImageExpireDays!==void 0)t.push({rulePriority:1,description:"Delete untagged images",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:e.untaggedImageExpireDays,countUnit:"days"},action:{type:"expire"}});if(e.maxImageCount!==void 0)t.push({rulePriority:t.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount},action:{type:"expire"}});if(e.maxImageAgeDays!==void 0)t.push({rulePriority:t.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:t}}static LifecyclePolicies={production:{maxImageCount:10,untaggedImageExpireDays:7},development:{maxImageCount:5,untaggedImageExpireDays:3},minimal:{maxImageCount:3,untaggedImageExpireDays:1},archive:{maxImageCount:50,untaggedImageExpireDays:30}};static enableImmutableTags(e){if(!e.Properties)e.Properties={};return e.Properties.ImageTagMutability="IMMUTABLE",e}static enableScanOnPush(e){if(!e.Properties)e.Properties={};return e.Properties.ImageScanningConfiguration={ScanOnPush:!0},e}static setLifecyclePolicy(e,t){if(!e.Properties)e.Properties={};return e.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(me.generateLifecyclePolicy(t))},e}static addCrossAccountAccess(e,t){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:t.map((a)=>`arn:aws:iam::${a}:root`)},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]},e}static addLambdaAccess(e){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"LambdaECRImageRetrievalPolicy",Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]},e}static generateBunDockerfile(e){let{baseImage:t="oven/bun:1-debian",serverPath:a,port:r=3000,additionalDirs:n=[],healthCheckEndpoint:i="/health",nodeCompatible:s=!1,envVars:o={},buildCommands:c=[],runCommand:l}=e,u=["app","config",...n],m=l||`bun run ${a}`,p=`# Multi-stage build for Bun application
|
|
23
|
+
`)}class Pe{static createBucket(e){let{name:t,bucketName:a,slug:r,environment:n,public:i=!1,versioning:s=!1,website:o=!1,encryption:c=!0,intelligentTiering:l=!1,cors:u,lifecycleRules:m}=e,p=a??A({slug:r,environment:n,resourceType:"s3",suffix:t}),g=f(p),h={Type:"AWS::S3::Bucket",Properties:{BucketName:p}};if(c)h.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(s)h.Properties.VersioningConfiguration={Status:"Enabled"};if(o)h.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!i)h.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(u&&u.length>0)h.Properties.CorsConfiguration={CorsRules:u.map((b)=>({AllowedOrigins:b.allowedOrigins,AllowedMethods:b.allowedMethods,AllowedHeaders:b.allowedHeaders,MaxAge:b.maxAge}))};if(m&&m.length>0)h.Properties.LifecycleConfiguration={Rules:m.map((b)=>({Id:b.id,Status:b.enabled?"Enabled":"Disabled",ExpirationInDays:b.expirationDays,Transitions:b.transitions?.map((T)=>({TransitionInDays:T.days,StorageClass:T.storageClass}))}))};if(l&&m){let b={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!h.Properties.LifecycleConfiguration)h.Properties.LifecycleConfiguration={Rules:[]};h.Properties.LifecycleConfiguration.Rules.push({Id:b.id,Status:"Enabled",Transitions:b.transitions?.map((T)=>({TransitionInDays:T.days,StorageClass:T.storageClass}))})}let y;if(i)y={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:C.Ref(g),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[C.Join("",[C.GetAtt(g,"Arn"),"/*"])]}]}}};return{bucket:h,bucketPolicy:y,logicalId:g}}static enableVersioning(e){if(!e.Properties)e.Properties={};return e.Properties.VersioningConfiguration={Status:"Enabled"},e}static enableWebsiteHosting(e,t="index.html",a="error.html"){if(!e.Properties)e.Properties={};return e.Properties.WebsiteConfiguration={IndexDocument:t,ErrorDocument:a},e}static setLifecycleRules(e,t){if(!e.Properties)e.Properties={};return e.Properties.LifecycleConfiguration={Rules:t.map((a)=>({Id:a.id,Status:a.enabled?"Enabled":"Disabled",ExpirationInDays:a.expirationDays,Transitions:a.transitions?.map((r)=>({TransitionInDays:r.days,StorageClass:r.storageClass}))}))},e}static enableIntelligentTiering(e){if(!e.Properties)e.Properties={};if(!e.Properties.LifecycleConfiguration)e.Properties.LifecycleConfiguration={Rules:[]};return e.Properties.LifecycleConfiguration.Rules.push({Id:"IntelligentTieringRule",Status:"Enabled",Transitions:[{TransitionInDays:0,StorageClass:"INTELLIGENT_TIERING"}]}),e}static addLambdaNotification(e,t){if(!e.Properties)e.Properties={};if(!e.Properties.NotificationConfiguration)e.Properties.NotificationConfiguration={};if(!e.Properties.NotificationConfiguration.LambdaConfigurations)e.Properties.NotificationConfiguration.LambdaConfigurations=[];let a={Event:t.events[0],Function:t.functionArn};if(t.filter)a.Filter={S3Key:{Rules:[...t.filter.prefix?[{Name:"prefix",Value:t.filter.prefix}]:[],...t.filter.suffix?[{Name:"suffix",Value:t.filter.suffix}]:[]]}};for(let r of t.events){let n={...a,Event:r};e.Properties.NotificationConfiguration.LambdaConfigurations.push(n)}return e}static Notifications={onObjectCreated:(e)=>({functionArn:e,events:["s3:ObjectCreated:*"]}),onObjectRemoved:(e)=>({functionArn:e,events:["s3:ObjectRemoved:*"]}),onImageUpload:(e,t)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:t,suffix:".jpg"}}),onFileType:(e,t,a)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:a,suffix:t}}),onFolderUpload:(e,t)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:t.endsWith("/")?t:`${t}/`}})};static createBackupPlan(e){let{name:t,slug:a,environment:r,bucketLogicalIds:n,retentionDays:i,schedule:s="cron(0 5 * * ? *)",vaultName:o,enableContinuousBackup:c=!1,moveToColdStorageAfterDays:l}=e,u=o||A({slug:a,environment:r,resourceType:"backup-vault",suffix:t}),m=f(u),p={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:u}},g=A({slug:a,environment:r,resourceType:"backup-role",suffix:t}),h=f(g),y={Type:"AWS::IAM::Role",Properties:{RoleName:g,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"backup.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup","arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"]}},b=A({slug:a,environment:r,resourceType:"backup-plan",suffix:t}),T=f(b),w={DeleteAfterDays:i};if(l&&l<i)w.MoveToColdStorageAfterDays=l;let S={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:b,BackupPlanRule:[{RuleName:`${t}-daily-backup`,TargetBackupVault:C.Ref(m),ScheduleExpression:s,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:w,EnableContinuousBackup:c}]}}},E=A({slug:a,environment:r,resourceType:"backup-selection",suffix:t}),v=f(E),P=n.map((I)=>C.GetAtt(I,"Arn")),N={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:C.Ref(T),BackupSelection:{SelectionName:E,IamRoleArn:C.GetAtt(h,"Arn"),Resources:P}}};return{vault:p,plan:S,selection:N,role:y,vaultLogicalId:m,planLogicalId:T,selectionLogicalId:v,roleLogicalId:h}}static BackupSchedules={HOURLY:"cron(0 * * * ? *)",DAILY_5AM:"cron(0 5 * * ? *)",DAILY_MIDNIGHT:"cron(0 0 * * ? *)",WEEKLY_SUNDAY:"cron(0 5 ? * SUN *)",WEEKLY_SATURDAY:"cron(0 5 ? * SAT *)",MONTHLY_FIRST:"cron(0 5 1 * ? *)",EVERY_12_HOURS:"cron(0 */12 * * ? *)",EVERY_6_HOURS:"cron(0 */6 * * ? *)"};static BackupRetention={ONE_DAY:1,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,THREE_MONTHS:90,SIX_MONTHS:180,ONE_YEAR:365,TWO_YEARS:730,FIVE_YEARS:1825,SEVEN_YEARS:2555};static createWwwRedirectBucket(e){let{slug:t,environment:a,sourceDomain:r,targetDomain:n,protocol:i="https"}=e,s=A({slug:t,environment:a,resourceType:"s3",suffix:"www-redirect"}),o=f(s),c={Type:"AWS::S3::Bucket",Properties:{BucketName:r,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:n,Protocol:i}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},l={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:C.Ref(o),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[C.Join("",[C.GetAtt(o,"Arn"),"/*"])]}]}}};return{bucket:c,bucketPolicy:l,logicalId:o}}static createDocsBucket(e){let{slug:t,environment:a,domain:r}=e,n=r||A({slug:t,environment:a,resourceType:"s3",suffix:"docs"}),i=f(n);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:n,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:i}}static createEmailBucket(e){let{slug:t,environment:a}=e,r=A({slug:t,environment:a,resourceType:"s3",suffix:"email"}),n=f(r),i={Type:"AWS::S3::Bucket",Properties:{BucketName:r,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"EmailRetention",Status:"Enabled",ExpirationInDays:90,Transitions:[{TransitionInDays:30,StorageClass:"STANDARD_IA"}]}]}}},s={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:C.Ref(n),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:C.Join("",[C.GetAtt(n,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":C.Ref("AWS::AccountId")}}}]}}};return{bucket:i,bucketPolicy:s,logicalId:n}}static docsExist(e={}){let{projectRoot:t=process.cwd(),docsPaths:a=["docs","documentation","doc"]}=e;for(let r of a){let n=Ae(t,r);if(je(n)){let i=["dist","build",".bunpress/dist","_site","out","public"];for(let s of i){let o=Ae(n,s);if(je(o))try{if(li(o).length>0)return{exists:!0,path:n,hasDistFolder:!0,distPath:o}}catch{}}return{exists:!0,path:n,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(e){let t=Pe.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!t.exists)return{bucket:null,logicalId:null,docsInfo:t};let a=Pe.createDocsBucket({slug:e.slug,environment:e.environment,domain:e.domain});return{bucket:a.bucket,bucketPolicy:a.bucketPolicy,logicalId:a.logicalId,docsInfo:t}}static createPrivateBucket(e){let{slug:t,environment:a,enableVersioning:r=!0,retentionDays:n,encryptionKeyArn:i}=e,s=A({slug:t,environment:a,resourceType:"s3",suffix:"private"}),o=f(s);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:s,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:i?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:i}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:r?{Status:"Enabled"}:void 0,LifecycleConfiguration:n?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:n}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:o}}static checkSourcePaths(e={}){let{projectRoot:t=process.cwd(),paths:a={}}=e,r=a.web||"views/web/dist",n=a.docs||"docs/dist",i=a.private||"private";return{web:{exists:je(Ae(t,r)),path:Ae(t,r)},docs:{exists:je(Ae(t,n)),path:Ae(t,n)},private:{exists:je(Ae(t,i)),path:Ae(t,i)}}}static createDeploymentBuckets(e){let{slug:t,environment:a,domain:r,projectRoot:n,paths:i}=e,s=Pe.checkSourcePaths({projectRoot:n,paths:i}),o={},c={web:!1,docs:!1,private:!1},l=Pe.createBucket({name:"web",slug:t,environment:a,public:!1,versioning:!1,encryption:!0});if(o[l.logicalId]=l.bucket,c.web=!0,s.docs.exists){let u=Pe.createDocsBucket({slug:t,environment:a,domain:r?`docs.${r}`:void 0});if(o[u.logicalId]=u.bucket,u.bucketPolicy)o[`${u.logicalId}Policy`]=u.bucketPolicy;c.docs=!0}if(s.private.exists){let u=Pe.createPrivateBucket({slug:t,environment:a,enableVersioning:!0});o[u.logicalId]=u.bucket,c.private=!0}return{resources:o,created:c,sourcePaths:s}}}class pe{static createRepository(e){let{name:t,slug:a,environment:r,scanOnPush:n=!0,imageMutability:i="MUTABLE",encryption:s="AES256",kmsKey:o,lifecyclePolicy:c,tags:l}=e,u=A({slug:a,environment:r,resourceType:"ecr",suffix:t}),m=f(u),p={Type:"AWS::ECR::Repository",Properties:{RepositoryName:u,ImageTagMutability:i,ImageScanningConfiguration:{ScanOnPush:n},EncryptionConfiguration:{EncryptionType:s,...o&&s==="KMS"?{KmsKey:o}:{}}}};if(c)p.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(pe.generateLifecyclePolicy(c))};if(l)p.Properties.Tags=Object.entries(l).map(([g,h])=>({Key:g,Value:h}));return{repository:p,logicalId:m}}static generateLifecyclePolicy(e){let t=[];if(e.untaggedImageExpireDays!==void 0)t.push({rulePriority:1,description:"Delete untagged images",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:e.untaggedImageExpireDays,countUnit:"days"},action:{type:"expire"}});if(e.maxImageCount!==void 0)t.push({rulePriority:t.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount},action:{type:"expire"}});if(e.maxImageAgeDays!==void 0)t.push({rulePriority:t.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:t}}static LifecyclePolicies={production:{maxImageCount:10,untaggedImageExpireDays:7},development:{maxImageCount:5,untaggedImageExpireDays:3},minimal:{maxImageCount:3,untaggedImageExpireDays:1},archive:{maxImageCount:50,untaggedImageExpireDays:30}};static enableImmutableTags(e){if(!e.Properties)e.Properties={};return e.Properties.ImageTagMutability="IMMUTABLE",e}static enableScanOnPush(e){if(!e.Properties)e.Properties={};return e.Properties.ImageScanningConfiguration={ScanOnPush:!0},e}static setLifecyclePolicy(e,t){if(!e.Properties)e.Properties={};return e.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(pe.generateLifecyclePolicy(t))},e}static addCrossAccountAccess(e,t){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:t.map((a)=>`arn:aws:iam::${a}:root`)},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]},e}static addLambdaAccess(e){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"LambdaECRImageRetrievalPolicy",Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]},e}static generateBunDockerfile(e){let{baseImage:t="oven/bun:1-debian",serverPath:a,port:r=3000,additionalDirs:n=[],healthCheckEndpoint:i="/health",nodeCompatible:s=!1,envVars:o={},buildCommands:c=[],runCommand:l}=e,u=["app","config",...n],m=l||`bun run ${a}`,p=`# Multi-stage build for Bun application
|
|
24
24
|
# Generated by ts-cloud
|
|
25
25
|
|
|
26
26
|
# Builder stage
|
|
@@ -74,7 +74,7 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\
|
|
|
74
74
|
|
|
75
75
|
# Start application
|
|
76
76
|
CMD ["bun", "run", "${a}"]
|
|
77
|
-
`,p}static generateDockerBuildCommands(e){let{repositoryUri:t,tag:a="latest",dockerfilePath:r="Dockerfile",context:n=".",additionalTags:i=[],buildArgs:s={},platform:o="linux/amd64",noCache:c=!1}=e,l=`${t}:${a}`,u=[a,...i],m=`docker build -f ${r} -t ${l}`;if(o)m+=` --platform ${o}`;if(c)m+=" --no-cache";for(let[h,y]of Object.entries(s))m+=` --build-arg ${h}=${y}`;m+=` ${n}`;let p=u.slice(1).map((h)=>`docker tag ${l} ${t}:${h}`),g=u.map((h)=>`docker push ${t}:${h}`);return{build:m,tag:p,push:g,all:[m,...p,...g]}}static generateEcrLoginCommand(e,t){return`aws ecr get-login-password --region ${e} | docker login --username AWS --password-stdin ${t}.dkr.ecr.${e}.amazonaws.com`}static buildRepositoryUri(e){return`${e.accountId}.dkr.ecr.${e.region}.amazonaws.com/${e.repositoryName}`}static generateImageTags(e){let t=["latest"];if(e.version){t.push(e.version);let a=e.version.split(".");if(a.length>=2)t.push(`${a[0]}.${a[1]}`);if(a.length>=1)t.push(a[0])}if(e.gitSha)t.push(e.gitSha.substring(0,7)),t.push(e.gitSha);if(e.gitBranch){let a=e.gitBranch.replace(/[^a-zA-Z0-9.-]/g,"-").replace(/^-+|-+$/g,"");t.push(a)}if(e.environment)t.push(e.environment);if(e.timestamp){let a=new Date().toISOString().replace(/[:.]/g,"-").substring(0,19);t.push(a)}return[...new Set(t)]}static DeploymentWorkflow={generateDeployScript:(e)=>{let t=
|
|
77
|
+
`,p}static generateDockerBuildCommands(e){let{repositoryUri:t,tag:a="latest",dockerfilePath:r="Dockerfile",context:n=".",additionalTags:i=[],buildArgs:s={},platform:o="linux/amd64",noCache:c=!1}=e,l=`${t}:${a}`,u=[a,...i],m=`docker build -f ${r} -t ${l}`;if(o)m+=` --platform ${o}`;if(c)m+=" --no-cache";for(let[h,y]of Object.entries(s))m+=` --build-arg ${h}=${y}`;m+=` ${n}`;let p=u.slice(1).map((h)=>`docker tag ${l} ${t}:${h}`),g=u.map((h)=>`docker push ${t}:${h}`);return{build:m,tag:p,push:g,all:[m,...p,...g]}}static generateEcrLoginCommand(e,t){return`aws ecr get-login-password --region ${e} | docker login --username AWS --password-stdin ${t}.dkr.ecr.${e}.amazonaws.com`}static buildRepositoryUri(e){return`${e.accountId}.dkr.ecr.${e.region}.amazonaws.com/${e.repositoryName}`}static generateImageTags(e){let t=["latest"];if(e.version){t.push(e.version);let a=e.version.split(".");if(a.length>=2)t.push(`${a[0]}.${a[1]}`);if(a.length>=1)t.push(a[0])}if(e.gitSha)t.push(e.gitSha.substring(0,7)),t.push(e.gitSha);if(e.gitBranch){let a=e.gitBranch.replace(/[^a-zA-Z0-9.-]/g,"-").replace(/^-+|-+$/g,"");t.push(a)}if(e.environment)t.push(e.environment);if(e.timestamp){let a=new Date().toISOString().replace(/[:.]/g,"-").substring(0,19);t.push(a)}return[...new Set(t)]}static DeploymentWorkflow={generateDeployScript:(e)=>{let t=pe.buildRepositoryUri({accountId:e.accountId,region:e.region,repositoryName:e.repositoryName}),a=e.tags||["latest"],r=a[0];return`#!/bin/bash
|
|
78
78
|
set -e
|
|
79
79
|
|
|
80
80
|
# Configuration
|
|
@@ -85,7 +85,7 @@ IMAGE_URI="${t}"
|
|
|
85
85
|
DOCKERFILE="${e.dockerfilePath||"Dockerfile"}"
|
|
86
86
|
|
|
87
87
|
echo "=== ECR Login ==="
|
|
88
|
-
${
|
|
88
|
+
${pe.generateEcrLoginCommand(e.region,e.accountId)}
|
|
89
89
|
|
|
90
90
|
echo "=== Building Image ==="
|
|
91
91
|
docker build -f $DOCKERFILE -t $IMAGE_URI:${r} --platform linux/amd64 .
|
|
@@ -103,7 +103,7 @@ echo "Image: $IMAGE_URI:${r}"
|
|
|
103
103
|
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
|
|
104
104
|
docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest`},...e.ecsCluster&&e.ecsService?[{name:"Deploy to ECS",run:`aws ecs update-service --cluster ${e.ecsCluster} --service ${e.ecsService} --force-new-deployment`}]:[]]}}};return`# Generated by ts-cloud
|
|
105
105
|
${JSON.stringify(t,null,2).replace(/"/g,"").replace(/,\n/g,`
|
|
106
|
-
`)}`}};static DockerfileTemplates={bunServer:(e,t=3000)=>
|
|
106
|
+
`)}`}};static DockerfileTemplates={bunServer:(e,t=3000)=>pe.generateBunDockerfile({serverPath:e,port:t}),bunWithBuild:(e,t,a=3000)=>pe.generateBunDockerfile({serverPath:e,port:a,buildCommands:[t]}),bunFullStack:(e,t=3000)=>pe.generateBunDockerfile({serverPath:e,port:t,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,t=3000)=>pe.generateBunDockerfile({serverPath:e,port:t,healthCheckEndpoint:"/api/health"})}}class ne{static createDistribution(e){let{slug:t,environment:a,origin:r,customDomain:n,certificateArn:i,errorPages:s,cachePolicy:o,edgeFunctions:c,http3:l=!1,comment:u}=e,m=A({slug:t,environment:a,resourceType:"cdn"}),p=f(m),g={Id:"DefaultOrigin",DomainName:r.domainName,OriginPath:r.originPath||""},h;if(r.type==="s3"){let b=`${p}OAC`;h={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${m}-oac`,Description:`Origin Access Control for ${m}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},g.OriginAccessControlId=C.Ref(b)}else if(r.type==="alb"||r.type==="custom")g.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let y={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:u||`CDN for ${m}`,DefaultRootObject:"index.html",Origins:[g],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:l?"http2and3":"http2"}}};if(n&&i)y.Properties.DistributionConfig.Aliases=[n],y.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:i,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(s&&s.length>0)y.Properties.DistributionConfig.CustomErrorResponses=s.map((b)=>({ErrorCode:b.errorCode,ResponseCode:b.responseCode,ResponsePagePath:b.responsePagePath}));if(c&&c.length>0)y.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=c.map((b)=>({EventType:b.event,LambdaFunctionARN:b.functionArn}));return{distribution:y,originAccessControl:h,logicalId:p}}static setCustomDomain(e,t,a){return e.Properties.DistributionConfig.Aliases=[t],e.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:a,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},e}static setErrorPages(e,t){return e.Properties.DistributionConfig.CustomErrorResponses=t.map((a)=>({ErrorCode:a.errorCode,ResponseCode:a.responseCode,ResponsePagePath:a.responsePagePath})),e}static enableHttp3(e){return e.Properties.DistributionConfig.HttpVersion="http2and3",e}static addEdgeFunction(e,t,a){if(!e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:t,LambdaFunctionARN:a}),e}static setCachePolicy(e,t){return e.Properties.DistributionConfig.Comment=`${e.Properties.DistributionConfig.Comment||""} (TTL: ${t.default||86400}s)`,e}static createSpaDistribution(e){return ne.createDistribution({...e,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(e){let{slug:t,environment:a}=e,r=A({slug:t,environment:a,resourceType:"edge-docs"}),n=f(r),i=f(`${r}-role`),s=f(`${r}-version`),o={Type:"AWS::IAM::Role",Properties:{RoleName:`${r}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","edgelambda.amazonaws.com"]},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}},c=`
|
|
107
107
|
'use strict';
|
|
108
108
|
|
|
109
109
|
exports.handler = async (event) => {
|
|
@@ -136,7 +136,7 @@ exports.handler = async (event) => {
|
|
|
136
136
|
|
|
137
137
|
return request;
|
|
138
138
|
};
|
|
139
|
-
`.trim();return{lambdaFunction:{Type:"AWS::Lambda::Function",Properties:{FunctionName:r,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:C.GetAtt(i,"Arn"),Code:{ZipFile:c},MemorySize:128,Timeout:5}},role:o,functionLogicalId:n,roleLogicalId:i,versionLogicalId:s}}static createDocsDistribution(e){let{slug:t,environment:a,origin:r,customDomain:n,certificateArn:i,lambdaEdgeFunctionArn:s}=e,o=
|
|
139
|
+
`.trim();return{lambdaFunction:{Type:"AWS::Lambda::Function",Properties:{FunctionName:r,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:C.GetAtt(i,"Arn"),Code:{ZipFile:c},MemorySize:128,Timeout:5}},role:o,functionLogicalId:n,roleLogicalId:i,versionLogicalId:s}}static createDocsDistribution(e){let{slug:t,environment:a,origin:r,customDomain:n,certificateArn:i,lambdaEdgeFunctionArn:s}=e,o=ne.createDistribution({slug:t,environment:a,origin:r,customDomain:n,certificateArn:i,comment:`Docs CDN for ${t}`,errorPages:[{errorCode:404,responseCode:404,responsePagePath:"/404.html"},{errorCode:403,responseCode:403,responsePagePath:"/404.html"}]});if(s)ne.addEdgeFunction(o.distribution,"origin-request",s);return o.distribution.Properties.DistributionConfig.DefaultCacheBehavior.DefaultTTL=86400,o.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MaxTTL=604800,o.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MinTTL=0,o}static createApiDistribution(e){let{slug:t,environment:a,albDomainName:r,customDomain:n,certificateArn:i,pathPattern:s="/api/*",forwardHeaders:o=["Host","Origin","Authorization","Content-Type","Accept"],forwardCookies:c="all",whitelistedCookies:l,customOriginHeaders:u={}}=e,m=A({slug:t,environment:a,resourceType:"cdn-api"}),p=f(m),g=Object.entries(u).map(([T,w])=>({HeaderName:T,HeaderValue:w})),h={Id:"ALBOrigin",DomainName:r,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(g.length>0)h.OriginCustomHeaders=g;let y={Forward:c};if(c==="whitelist"&&l)y.WhitelistedNames=l;let b={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`API CDN for ${m}`,Origins:[h],DefaultCacheBehavior:{TargetOriginId:"ALBOrigin",ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:0,MaxTTL:0,MinTTL:0,ForwardedValues:{QueryString:!0,Headers:o,Cookies:y}},PriceClass:"PriceClass_100",HttpVersion:"http2"}}};if(n&&i)b.Properties.DistributionConfig.Aliases=[n],b.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:i,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:b,logicalId:p}}static createMultiOriginDistribution(e){let{slug:t,environment:a,s3BucketDomainName:r,albDomainName:n,apiPathPattern:i="/api/*",customDomain:s,certificateArn:o,customOriginHeaders:c={}}=e,l=A({slug:t,environment:a,resourceType:"cdn"}),u=f(l),m=`${u}OAC`,p={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${l}-oac`,Description:`Origin Access Control for ${l}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},g=Object.entries(c).map(([T,w])=>({HeaderName:T,HeaderValue:w})),h={Id:"S3Origin",DomainName:r,OriginAccessControlId:C.Ref(m)},y={Id:"ALBOrigin",DomainName:n,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(g.length>0)y.OriginCustomHeaders=g;let b={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`Multi-origin CDN for ${l}`,DefaultRootObject:"index.html",Origins:[h,y],DefaultCacheBehavior:{TargetOriginId:"S3Origin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},CacheBehaviors:[{PathPattern:i,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(s&&o)b.Properties.DistributionConfig.Aliases=[s],b.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:o,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:b,originAccessControl:p,logicalId:u,oacLogicalId:m}}static addAlbOrigin(e,t){let{originId:a,domainName:r,pathPattern:n,customHeaders:i={},forwardHeaders:s=["Host","Origin","Authorization","Content-Type","Accept"],cacheTtl:o={default:0,max:0,min:0}}=t,c=Object.entries(i).map(([u,m])=>({HeaderName:u,HeaderValue:m})),l={Id:a,DomainName:r,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(c.length>0)l.OriginCustomHeaders=c;if(!e.Properties.DistributionConfig.Origins)e.Properties.DistributionConfig.Origins=[];if(e.Properties.DistributionConfig.Origins.push(l),!e.Properties.DistributionConfig.CacheBehaviors)e.Properties.DistributionConfig.CacheBehaviors=[];return e.Properties.DistributionConfig.CacheBehaviors.push({PathPattern:n,TargetOriginId:a,ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:o.default,MaxTTL:o.max,MinTTL:o.min,ForwardedValues:{QueryString:!0,Headers:s,Cookies:{Forward:"all"}}}),e}static addOriginHeader(e,t,a,r){let n=e.Properties.DistributionConfig.Origins?.find((i)=>i.Id===t);if(n){if(!n.OriginCustomHeaders)n.OriginCustomHeaders=[];n.OriginCustomHeaders.push({HeaderName:a,HeaderValue:r})}return e}static EdgeFunctionTemplates={docsOriginRequest:`
|
|
140
140
|
'use strict';
|
|
141
141
|
exports.handler = async (event) => {
|
|
142
142
|
const request = event.Records[0].cf.request;
|
|
@@ -209,7 +209,7 @@ exports.handler = async (event) => {
|
|
|
209
209
|
|
|
210
210
|
return request;
|
|
211
211
|
};
|
|
212
|
-
`.trim()};static Config={ttl:(e)=>{let{min:t=0,max:a=86400,default:r=86400}=e;return{MinTTL:t,MaxTTL:a,DefaultTTL:r}},cookies:(e,t)=>{let a={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&t)a.WhitelistedNames=t;return a},allowedMethods:(e)=>{let t={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return t[e]||t.GET_HEAD},cachedMethods:(e)=>{let t={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return t[e]||t.GET_HEAD},ttlPresets:{static:{min:0,max:31536000,default:31536000},dynamic:{min:0,max:0,default:0},api:{min:0,max:3600,default:60},html:{min:0,max:86400,default:86400},images:{min:0,max:604800,default:604800}},cacheBehavior:(e)=>{let{ttl:t={min:0,max:86400,default:86400},cookies:a="none",allowedCookies:r,allowedMethods:n="GET_HEAD",cachedMethods:i="GET_HEAD",compress:s=!0,forwardQueryString:o=!0,forwardHeaders:c=[]}=e;return{MinTTL:t.min,MaxTTL:t.max,DefaultTTL:t.default,Compress:s,AllowedMethods:re.Config.allowedMethods(n),CachedMethods:re.Config.cachedMethods(i),ForwardedValues:{QueryString:o,Headers:c,Cookies:re.Config.cookies(a,r)}}}};static applyConfig(e,t){let a=e.Properties.DistributionConfig.DefaultCacheBehavior;if(t.ttl)a.MinTTL=t.ttl.min,a.MaxTTL=t.ttl.max,a.DefaultTTL=t.ttl.default;if(t.compress!==void 0)a.Compress=t.compress;if(t.allowedMethods)a.AllowedMethods=re.Config.allowedMethods(t.allowedMethods);if(t.cachedMethods)a.CachedMethods=re.Config.cachedMethods(t.cachedMethods);if(t.cookies){if(!a.ForwardedValues)a.ForwardedValues={QueryString:!0};a.ForwardedValues.Cookies=re.Config.cookies(t.cookies,t.allowedCookies)}return e}}class q{static createHostedZone(e){let{domain:t,slug:a,environment:r,comment:n}=e,i=A({slug:a,environment:r,resourceType:"hostedzone"}),s=f(`${i}-${t.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:t,HostedZoneConfig:{Comment:n||`Hosted zone for ${t}`}}},logicalId:s}}static createRecord(e){let{hostedZoneId:t,hostedZoneName:a,name:r,type:n,ttl:i,values:s,aliasTarget:o}=e,c=f(`record-${r.replace(/\./g,"")}-${n}`),l={Type:"AWS::Route53::RecordSet",Properties:{Name:r,Type:n}};if(t)l.Properties.HostedZoneId=t;else if(a)l.Properties.HostedZoneName=a;if(o)l.Properties.AliasTarget={DNSName:o.dnsName,HostedZoneId:o.hostedZoneId,EvaluateTargetHealth:o.evaluateTargetHealth??!1};else l.Properties.TTL=i||300,l.Properties.ResourceRecords=s||[];return{record:l,logicalId:c}}static createCloudFrontAlias(e,t,a){return q.createRecord({hostedZoneId:a,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,t,a,r){return q.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:a,evaluateTargetHealth:!0}})}static createCname(e,t,a,r=300){return q.createRecord({hostedZoneId:a,name:e,type:"CNAME",ttl:r,values:[t]})}static createWwwRedirect(e,t){return q.createRecord({hostedZoneId:t,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,t,a,r=300){return q.createRecord({hostedZoneId:a,name:e,type:"MX",ttl:r,values:t.map((n)=>`${n.priority} ${n.server}`)})}static createTxtRecord(e,t,a,r=300){return q.createRecord({hostedZoneId:a,name:e,type:"TXT",ttl:r,values:[`"${t}"`]})}static createSpfRecord(e,t,a){return q.createTxtRecord(e,t,a)}static createDmarcRecord(e,t,a,r){let n=`v=DMARC1; p=${t}; rua=mailto:${a}`;return q.createTxtRecord(`_dmarc.${e}`,n,r)}static createS3WebsiteAlias(e,t,a,r){return q.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:a,evaluateTargetHealth:!1}})}static S3WebsiteHostedZoneIds={"us-east-1":"Z3AQBSTGFYJSTF","us-east-2":"Z2O1EMRO9K5GLX","us-west-1":"Z2F56UZL2M1ACD","us-west-2":"Z3BJ6K6RIION7M","af-south-1":"Z83WF9RJE8B12","ap-east-1":"ZNB98KWMFR0R6","ap-south-1":"Z11RGJOFQNVJUP","ap-south-2":"Z02976202B4EZMXIPMXF7","ap-northeast-1":"Z2M4EHUR26P7ZW","ap-northeast-2":"Z3W03O7B5YMIYP","ap-northeast-3":"Z2YQB5RD63NC85","ap-southeast-1":"Z3O0J2DXBE1FTB","ap-southeast-2":"Z1WCIBER6CPFUU","ap-southeast-3":"Z01613992JD795ZI93075","ca-central-1":"Z1QDHH18159H29","eu-central-1":"Z21DNDUVLTQW6Q","eu-central-2":"Z030506016YDQGETNASS","eu-west-1":"Z1BKCTXD74EZPE","eu-west-2":"Z3GKZC51ZF0DB4","eu-west-3":"Z3R1K369G5AVDG","eu-north-1":"Z3BAZG2TWCNX0D","eu-south-1":"Z30OZKI7KPW7MI","eu-south-2":"Z0081959F7139GRJC19J","me-south-1":"Z1MPMWCPA7YB62","me-central-1":"Z06143092I8HRBER9VXCO","sa-east-1":"Z7KQH4QJS55SO"};static getS3WebsiteEndpoint(e,t){return`${e}.s3-website-${t}.amazonaws.com`}static createStoreRecord(e,t,a){return q.createCname(`store.${e}`,t,a)}static createApiRecord(e,t,a){return q.createCname(`api.${e}`,t,a)}static createDocsRecord(e,t,a){return q.createCname(`docs.${e}`,t,a)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class U{static createCertificate(e){let{domain:t,subdomains:a=[],slug:r,environment:n,validationMethod:i="DNS",hostedZoneId:s}=e,o=A({slug:r,environment:n,resourceType:"acm"}),c=f(`${o}-${t.replace(/\./g,"")}`),l=[t];for(let m of a)if(m==="*")l.push(`*.${t}`);else l.push(`${m}.${t}`);let u={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:t,SubjectAlternativeNames:l,ValidationMethod:i}};if(i==="DNS"&&s)u.Properties.DomainValidationOptions=l.map((m)=>({DomainName:m,HostedZoneId:s}));return{certificate:u,logicalId:c}}static createKmsKey(e){let{description:t,slug:a,environment:r,enableRotation:n=!0,multiRegion:i=!1}=e,s=A({slug:a,environment:r,resourceType:"kms"}),o=f(s),c={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:C.Sub("arn:aws:iam::${AWS::AccountId}:root")},Action:"kms:*",Resource:"*"},{Sid:"Allow services to use the key",Effect:"Allow",Principal:{Service:["s3.amazonaws.com","cloudfront.amazonaws.com","logs.amazonaws.com","secretsmanager.amazonaws.com"]},Action:["kms:Decrypt","kms:GenerateDataKey"],Resource:"*"}]},l={Type:"AWS::KMS::Key",Properties:{Description:t,Enabled:!0,EnableKeyRotation:n,KeyPolicy:c,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:i}},u=f(`${s}-alias`),m={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${a}-${r}`,TargetKeyId:C.Ref(o)}};return{key:l,alias:m,logicalId:o,aliasId:u}}static createFirewall(e){let{slug:t,environment:a,scope:r="CLOUDFRONT",defaultAction:n="allow"}=e,i=A({slug:t,environment:a,resourceType:"waf"}),s=f(i);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:i,Scope:r,DefaultAction:n==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${t} ${a}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-metric`}}},logicalId:s}}static setRateLimit(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{RateBasedStatement:{Limit:t.requestsPerWindow,AggregateKeyType:t.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static blockCountries(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{GeoMatchStatement:{CountryCodes:t.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static blockIpAddresses(e,t,a,r){let n=A({slug:a,environment:r,resourceType:"ipset"}),i=f(`${n}-${t.name}`),s={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${n}-${t.name}`,Scope:e.Properties.Scope,IPAddressVersion:t.ipVersion||"IPV4",Addresses:t.ipAddresses,Description:`Blocked IPs for ${t.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{IPSetReferenceStatement:{Arn:C.GetAtt(i,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),{webAcl:e,ipSet:s,ipSetLogicalId:i}}static addManagedRules(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];let a={ManagedRuleGroupStatement:{VendorName:t.vendorName,Name:t.ruleName}};if(t.excludedRules&&t.excludedRules.length>0)a.ManagedRuleGroupStatement.ExcludedRules=t.excludedRules.map((r)=>({Name:r}));return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:a,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static ManagedRuleGroups={CoreRuleSet:{vendorName:"AWS",ruleName:"AWSManagedRulesCommonRuleSet"},KnownBadInputs:{vendorName:"AWS",ruleName:"AWSManagedRulesKnownBadInputsRuleSet"},SqlDatabase:{vendorName:"AWS",ruleName:"AWSManagedRulesSQLiRuleSet"},LinuxOS:{vendorName:"AWS",ruleName:"AWSManagedRulesLinuxRuleSet"},PosixOS:{vendorName:"AWS",ruleName:"AWSManagedRulesUnixRuleSet"},AmazonIpReputation:{vendorName:"AWS",ruleName:"AWSManagedRulesAmazonIpReputationList"},AnonymousIpList:{vendorName:"AWS",ruleName:"AWSManagedRulesAnonymousIpList"},BotControl:{vendorName:"AWS",ruleName:"AWSManagedRulesBotControlRuleSet"}};static setPathRateLimit(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];let a=t.paths.map((r)=>({SearchString:r,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{RateBasedStatement:{Limit:t.requestsPerWindow,AggregateKeyType:t.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:a.map((r)=>({ByteMatchStatement:r}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static setHeaderRateLimit(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];let a={RateBasedStatement:{Limit:t.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:t.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(t.headerValue)a.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:t.headerValue,FieldToMatch:{SingleHeader:{Name:t.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:a,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static protectLoginEndpoint(e,t){let{loginPaths:a,priority:r,requestsPerMinute:n=10}=t;return U.setPathRateLimit(e,{name:"LoginRateLimit",priority:r,requestsPerWindow:n*5,paths:a}),e}static protectApiEndpoints(e,t){let{apiPaths:a,priority:r,requestsPerMinute:n=100}=t;return U.setPathRateLimit(e,{name:"ApiRateLimit",priority:r,requestsPerWindow:n*5,paths:a}),e}static createProtectedFirewall(e){let{slug:t,environment:a,scope:r="CLOUDFRONT",enableBotControl:n=!1,enableRateLimiting:i=!0,rateLimitPerMinute:s=2000}=e,{webAcl:o,logicalId:c}=U.createFirewall({slug:t,environment:a,scope:r,defaultAction:"allow"}),l=0;if(o=U.addManagedRules(o,{name:"AWSIPReputationList",priority:l++,...U.ManagedRuleGroups.AmazonIpReputation}),o=U.addManagedRules(o,{name:"AWSAnonymousIPList",priority:l++,...U.ManagedRuleGroups.AnonymousIpList}),o=U.addManagedRules(o,{name:"AWSCoreRuleSet",priority:l++,...U.ManagedRuleGroups.CoreRuleSet}),o=U.addManagedRules(o,{name:"AWSKnownBadInputs",priority:l++,...U.ManagedRuleGroups.KnownBadInputs}),o=U.addManagedRules(o,{name:"AWSSQLi",priority:l++,...U.ManagedRuleGroups.SqlDatabase}),n)o=U.addManagedRules(o,{name:"AWSBotControl",priority:l++,...U.ManagedRuleGroups.BotControl});if(i)o=U.setRateLimit(o,{name:"GlobalRateLimit",priority:l++,requestsPerWindow:s*5});return{webAcl:o,logicalId:c}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}class k{static createServer(e){let{slug:t,environment:a,instanceType:r="t3.micro",imageId:n="ami-0f3caa1cf4417e51b",keyName:i,securityGroupIds:s,subnetId:o,userData:c,volumeSize:l=20,volumeType:u="gp3",encrypted:m=!0}=e,p=A({slug:t,environment:a,resourceType:"ec2"}),g=f(p),h={Type:"AWS::EC2::Instance",Properties:{ImageId:n,InstanceType:r,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:a}]}};if(i)h.Properties.KeyName=i;if(s)h.Properties.SecurityGroupIds=s;if(o)h.Properties.SubnetId=o;if(c)h.Properties.UserData=C.Base64(c);return h.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:l,VolumeType:u,Encrypted:m,DeleteOnTermination:!0}}],{instance:h,logicalId:g}}static createSecurityGroup(e){let{slug:t,environment:a,vpcId:r,description:n,ingress:i=[],egress:s=[]}=e,o=A({slug:t,environment:a,resourceType:"sg"}),c=f(o),l={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:n||`Security group for ${t} ${a}`,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:a}]}};if(r)l.Properties.VpcId=r;if(i.length>0)l.Properties.SecurityGroupIngress=i.map((u)=>({IpProtocol:u.protocol,FromPort:u.fromPort,ToPort:u.toPort,CidrIp:u.cidr,SourceSecurityGroupId:u.sourceSecurityGroupId}));if(s.length>0)l.Properties.SecurityGroupEgress=s.map((u)=>({IpProtocol:u.protocol,FromPort:u.fromPort,ToPort:u.toPort,CidrIp:u.cidr,DestinationSecurityGroupId:u.sourceSecurityGroupId}));return{securityGroup:l,logicalId:c}}static createWebServerSecurityGroup(e,t,a){return k.createSecurityGroup({slug:e,environment:t,vpcId:a,description:"Security group for web servers - HTTP, HTTPS, SSH",ingress:[{protocol:"tcp",fromPort:80,toPort:80,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:443,toPort:443,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:22,toPort:22,cidr:"0.0.0.0/0"}],egress:[{protocol:"-1",fromPort:0,toPort:0,cidr:"0.0.0.0/0"}]})}static createLoadBalancer(e){let{slug:t,environment:a,scheme:r="internet-facing",subnets:n,securityGroups:i,type:s="application"}=e,o=A({slug:t,environment:a,resourceType:"alb"}),c=f(o),l={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:o,Scheme:r,Type:s,Subnets:n,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:a}]}};if(i)l.Properties.SecurityGroups=i;return{loadBalancer:l,logicalId:c}}static createTargetGroup(e){let{slug:t,environment:a,port:r,protocol:n="HTTP",vpcId:i,targetType:s="ip",healthCheckPath:o="/",healthCheckInterval:c=30,healthCheckTimeout:l=5,healthyThreshold:u=2,unhealthyThreshold:m=3}=e,p=A({slug:t,environment:a,resourceType:"tg"}),g=f(p);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:p,Port:r,Protocol:n,VpcId:i,TargetType:s,HealthCheckEnabled:!0,HealthCheckProtocol:n,HealthCheckPath:o,HealthCheckIntervalSeconds:c,HealthCheckTimeoutSeconds:l,HealthyThresholdCount:u,UnhealthyThresholdCount:m,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:a}]}},logicalId:g}}static createListener(e,t){let{port:a,protocol:r="HTTP",certificateArn:n,defaultTargetGroupArn:i}=t,s=f(`listener-${e}-${a}`),o={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:C.Ref(e),Port:a,Protocol:r,DefaultActions:[{Type:"forward",TargetGroupArn:i}]}};if(r==="HTTPS"&&n)o.Properties.Certificates=[{CertificateArn:n}],o.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:o,logicalId:s}}static createEcsCluster(e,t){let a=A({slug:e,environment:t,resourceType:"ecs-cluster"}),r=f(a);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:a,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:t}]}},logicalId:r}}static createFargateService(e){let{slug:t,environment:a,image:r,cpu:n="256",memory:i="512",desiredCount:s=1,containerPort:o=8080,environmentVariables:c={},secrets:l=[],healthCheck:u,logGroup:m,subnets:p,securityGroups:g,targetGroupArn:h}=e,{cluster:y,logicalId:b}=k.createEcsCluster(t,a),T=A({slug:t,environment:a,resourceType:"fargate"}),w=f(`${T}-execution-role`),S={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"]}},E=f(`${T}-task-role`),v={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},P=f(`${T}-task`),N={Type:"AWS::ECS::TaskDefinition",Properties:{Family:T,TaskRoleArn:C.GetAtt(E,"Arn"),ExecutionRoleArn:C.GetAtt(w,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:n,Memory:i,ContainerDefinitions:[{Name:t,Image:r,Essential:!0,PortMappings:[{ContainerPort:o,Protocol:"tcp"}],Environment:Object.entries(c).map(([M,O])=>({Name:M,Value:O})),Secrets:l.map((M)=>({Name:M.name,ValueFrom:M.valueFrom}))}],Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:a}]}};if(u)N.Properties.ContainerDefinitions[0].HealthCheck={Command:u.command,Interval:u.interval||30,Timeout:u.timeout||5,Retries:u.retries||3,StartPeriod:60};if(m)N.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":m,"awslogs-region":C.Ref("AWS::Region"),"awslogs-stream-prefix":t}};let I=f(`${T}-service`),D={Type:"AWS::ECS::Service",Properties:{ServiceName:T,Cluster:C.Ref(b),TaskDefinition:C.Ref(P),DesiredCount:s,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:p,SecurityGroups:g,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:a}]}};if(h)D.Properties.LoadBalancers=[{TargetGroupArn:h,ContainerName:t,ContainerPort:o}];return{cluster:y,taskDefinition:N,service:D,taskRole:v,executionRole:S,clusterLogicalId:b,taskDefinitionLogicalId:P,serviceLogicalId:I,taskRoleLogicalId:E,executionRoleLogicalId:w}}static createLambdaFunction(e){let{slug:t,environment:a,runtime:r,handler:n,code:i,timeout:s=30,memorySize:o=128,environmentVariables:c={},vpcConfig:l}=e,u=A({slug:t,environment:a,resourceType:"lambda"}),m=f(u),p=f(`${u}-role`),g={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}};if(l)g.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let h={Type:"AWS::Lambda::Function",Properties:{FunctionName:u,Runtime:r,Role:C.GetAtt(p,"Arn"),Handler:n,Code:{...i.s3Bucket&&{S3Bucket:i.s3Bucket},...i.s3Key&&{S3Key:i.s3Key},...i.zipFile&&{ZipFile:i.zipFile}},Timeout:s,MemorySize:o,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:a}]}};if(Object.keys(c).length>0)h.Properties.Environment={Variables:c};if(l)h.Properties.VpcConfig={SecurityGroupIds:l.securityGroupIds,SubnetIds:l.subnetIds};return{lambdaFunction:h,role:g,logicalId:m,roleLogicalId:p}}static generateNodeServerUserData(e={}){let{nodeVersion:t="20",appRepo:a,environment:r={}}=e,n=Object.entries(r).map(([i,s])=>`echo "export ${i}='${s}'" >> /etc/environment`).join(`
|
|
212
|
+
`.trim()};static Config={ttl:(e)=>{let{min:t=0,max:a=86400,default:r=86400}=e;return{MinTTL:t,MaxTTL:a,DefaultTTL:r}},cookies:(e,t)=>{let a={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&t)a.WhitelistedNames=t;return a},allowedMethods:(e)=>{let t={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return t[e]||t.GET_HEAD},cachedMethods:(e)=>{let t={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return t[e]||t.GET_HEAD},ttlPresets:{static:{min:0,max:31536000,default:31536000},dynamic:{min:0,max:0,default:0},api:{min:0,max:3600,default:60},html:{min:0,max:86400,default:86400},images:{min:0,max:604800,default:604800}},cacheBehavior:(e)=>{let{ttl:t={min:0,max:86400,default:86400},cookies:a="none",allowedCookies:r,allowedMethods:n="GET_HEAD",cachedMethods:i="GET_HEAD",compress:s=!0,forwardQueryString:o=!0,forwardHeaders:c=[]}=e;return{MinTTL:t.min,MaxTTL:t.max,DefaultTTL:t.default,Compress:s,AllowedMethods:ne.Config.allowedMethods(n),CachedMethods:ne.Config.cachedMethods(i),ForwardedValues:{QueryString:o,Headers:c,Cookies:ne.Config.cookies(a,r)}}}};static applyConfig(e,t){let a=e.Properties.DistributionConfig.DefaultCacheBehavior;if(t.ttl)a.MinTTL=t.ttl.min,a.MaxTTL=t.ttl.max,a.DefaultTTL=t.ttl.default;if(t.compress!==void 0)a.Compress=t.compress;if(t.allowedMethods)a.AllowedMethods=ne.Config.allowedMethods(t.allowedMethods);if(t.cachedMethods)a.CachedMethods=ne.Config.cachedMethods(t.cachedMethods);if(t.cookies){if(!a.ForwardedValues)a.ForwardedValues={QueryString:!0};a.ForwardedValues.Cookies=ne.Config.cookies(t.cookies,t.allowedCookies)}return e}}class q{static createHostedZone(e){let{domain:t,slug:a,environment:r,comment:n}=e,i=A({slug:a,environment:r,resourceType:"hostedzone"}),s=f(`${i}-${t.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:t,HostedZoneConfig:{Comment:n||`Hosted zone for ${t}`}}},logicalId:s}}static createRecord(e){let{hostedZoneId:t,hostedZoneName:a,name:r,type:n,ttl:i,values:s,aliasTarget:o}=e,c=f(`record-${r.replace(/\./g,"")}-${n}`),l={Type:"AWS::Route53::RecordSet",Properties:{Name:r,Type:n}};if(t)l.Properties.HostedZoneId=t;else if(a)l.Properties.HostedZoneName=a;if(o)l.Properties.AliasTarget={DNSName:o.dnsName,HostedZoneId:o.hostedZoneId,EvaluateTargetHealth:o.evaluateTargetHealth??!1};else l.Properties.TTL=i||300,l.Properties.ResourceRecords=s||[];return{record:l,logicalId:c}}static createCloudFrontAlias(e,t,a){return q.createRecord({hostedZoneId:a,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,t,a,r){return q.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:a,evaluateTargetHealth:!0}})}static createCname(e,t,a,r=300){return q.createRecord({hostedZoneId:a,name:e,type:"CNAME",ttl:r,values:[t]})}static createWwwRedirect(e,t){return q.createRecord({hostedZoneId:t,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,t,a,r=300){return q.createRecord({hostedZoneId:a,name:e,type:"MX",ttl:r,values:t.map((n)=>`${n.priority} ${n.server}`)})}static createTxtRecord(e,t,a,r=300){return q.createRecord({hostedZoneId:a,name:e,type:"TXT",ttl:r,values:[`"${t}"`]})}static createSpfRecord(e,t,a){return q.createTxtRecord(e,t,a)}static createDmarcRecord(e,t,a,r){let n=`v=DMARC1; p=${t}; rua=mailto:${a}`;return q.createTxtRecord(`_dmarc.${e}`,n,r)}static createS3WebsiteAlias(e,t,a,r){return q.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:t,hostedZoneId:a,evaluateTargetHealth:!1}})}static S3WebsiteHostedZoneIds={"us-east-1":"Z3AQBSTGFYJSTF","us-east-2":"Z2O1EMRO9K5GLX","us-west-1":"Z2F56UZL2M1ACD","us-west-2":"Z3BJ6K6RIION7M","af-south-1":"Z83WF9RJE8B12","ap-east-1":"ZNB98KWMFR0R6","ap-south-1":"Z11RGJOFQNVJUP","ap-south-2":"Z02976202B4EZMXIPMXF7","ap-northeast-1":"Z2M4EHUR26P7ZW","ap-northeast-2":"Z3W03O7B5YMIYP","ap-northeast-3":"Z2YQB5RD63NC85","ap-southeast-1":"Z3O0J2DXBE1FTB","ap-southeast-2":"Z1WCIBER6CPFUU","ap-southeast-3":"Z01613992JD795ZI93075","ca-central-1":"Z1QDHH18159H29","eu-central-1":"Z21DNDUVLTQW6Q","eu-central-2":"Z030506016YDQGETNASS","eu-west-1":"Z1BKCTXD74EZPE","eu-west-2":"Z3GKZC51ZF0DB4","eu-west-3":"Z3R1K369G5AVDG","eu-north-1":"Z3BAZG2TWCNX0D","eu-south-1":"Z30OZKI7KPW7MI","eu-south-2":"Z0081959F7139GRJC19J","me-south-1":"Z1MPMWCPA7YB62","me-central-1":"Z06143092I8HRBER9VXCO","sa-east-1":"Z7KQH4QJS55SO"};static getS3WebsiteEndpoint(e,t){return`${e}.s3-website-${t}.amazonaws.com`}static createStoreRecord(e,t,a){return q.createCname(`store.${e}`,t,a)}static createApiRecord(e,t,a){return q.createCname(`api.${e}`,t,a)}static createDocsRecord(e,t,a){return q.createCname(`docs.${e}`,t,a)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class G{static createCertificate(e){let{domain:t,subdomains:a=[],slug:r,environment:n,validationMethod:i="DNS",hostedZoneId:s}=e,o=A({slug:r,environment:n,resourceType:"acm"}),c=f(`${o}-${t.replace(/\./g,"")}`),l=[t];for(let m of a)if(m==="*")l.push(`*.${t}`);else l.push(`${m}.${t}`);let u={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:t,SubjectAlternativeNames:l,ValidationMethod:i}};if(i==="DNS"&&s)u.Properties.DomainValidationOptions=l.map((m)=>({DomainName:m,HostedZoneId:s}));return{certificate:u,logicalId:c}}static createKmsKey(e){let{description:t,slug:a,environment:r,enableRotation:n=!0,multiRegion:i=!1}=e,s=A({slug:a,environment:r,resourceType:"kms"}),o=f(s),c={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:C.Sub("arn:aws:iam::${AWS::AccountId}:root")},Action:"kms:*",Resource:"*"},{Sid:"Allow services to use the key",Effect:"Allow",Principal:{Service:["s3.amazonaws.com","cloudfront.amazonaws.com","logs.amazonaws.com","secretsmanager.amazonaws.com"]},Action:["kms:Decrypt","kms:GenerateDataKey"],Resource:"*"}]},l={Type:"AWS::KMS::Key",Properties:{Description:t,Enabled:!0,EnableKeyRotation:n,KeyPolicy:c,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:i}},u=f(`${s}-alias`),m={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${a}-${r}`,TargetKeyId:C.Ref(o)}};return{key:l,alias:m,logicalId:o,aliasId:u}}static createFirewall(e){let{slug:t,environment:a,scope:r="CLOUDFRONT",defaultAction:n="allow"}=e,i=A({slug:t,environment:a,resourceType:"waf"}),s=f(i);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:i,Scope:r,DefaultAction:n==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${t} ${a}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i}-metric`}}},logicalId:s}}static setRateLimit(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{RateBasedStatement:{Limit:t.requestsPerWindow,AggregateKeyType:t.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static blockCountries(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{GeoMatchStatement:{CountryCodes:t.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static blockIpAddresses(e,t,a,r){let n=A({slug:a,environment:r,resourceType:"ipset"}),i=f(`${n}-${t.name}`),s={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${n}-${t.name}`,Scope:e.Properties.Scope,IPAddressVersion:t.ipVersion||"IPV4",Addresses:t.ipAddresses,Description:`Blocked IPs for ${t.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{IPSetReferenceStatement:{Arn:C.GetAtt(i,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),{webAcl:e,ipSet:s,ipSetLogicalId:i}}static addManagedRules(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];let a={ManagedRuleGroupStatement:{VendorName:t.vendorName,Name:t.ruleName}};if(t.excludedRules&&t.excludedRules.length>0)a.ManagedRuleGroupStatement.ExcludedRules=t.excludedRules.map((r)=>({Name:r}));return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:a,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static ManagedRuleGroups={CoreRuleSet:{vendorName:"AWS",ruleName:"AWSManagedRulesCommonRuleSet"},KnownBadInputs:{vendorName:"AWS",ruleName:"AWSManagedRulesKnownBadInputsRuleSet"},SqlDatabase:{vendorName:"AWS",ruleName:"AWSManagedRulesSQLiRuleSet"},LinuxOS:{vendorName:"AWS",ruleName:"AWSManagedRulesLinuxRuleSet"},PosixOS:{vendorName:"AWS",ruleName:"AWSManagedRulesUnixRuleSet"},AmazonIpReputation:{vendorName:"AWS",ruleName:"AWSManagedRulesAmazonIpReputationList"},AnonymousIpList:{vendorName:"AWS",ruleName:"AWSManagedRulesAnonymousIpList"},BotControl:{vendorName:"AWS",ruleName:"AWSManagedRulesBotControlRuleSet"}};static setPathRateLimit(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];let a=t.paths.map((r)=>({SearchString:r,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:{RateBasedStatement:{Limit:t.requestsPerWindow,AggregateKeyType:t.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:a.map((r)=>({ByteMatchStatement:r}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static setHeaderRateLimit(e,t){if(!e.Properties.Rules)e.Properties.Rules=[];let a={RateBasedStatement:{Limit:t.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:t.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(t.headerValue)a.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:t.headerValue,FieldToMatch:{SingleHeader:{Name:t.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:t.name,Priority:t.priority,Statement:a,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${t.name}-metric`}}),e}static protectLoginEndpoint(e,t){let{loginPaths:a,priority:r,requestsPerMinute:n=10}=t;return G.setPathRateLimit(e,{name:"LoginRateLimit",priority:r,requestsPerWindow:n*5,paths:a}),e}static protectApiEndpoints(e,t){let{apiPaths:a,priority:r,requestsPerMinute:n=100}=t;return G.setPathRateLimit(e,{name:"ApiRateLimit",priority:r,requestsPerWindow:n*5,paths:a}),e}static createProtectedFirewall(e){let{slug:t,environment:a,scope:r="CLOUDFRONT",enableBotControl:n=!1,enableRateLimiting:i=!0,rateLimitPerMinute:s=2000}=e,{webAcl:o,logicalId:c}=G.createFirewall({slug:t,environment:a,scope:r,defaultAction:"allow"}),l=0;if(o=G.addManagedRules(o,{name:"AWSIPReputationList",priority:l++,...G.ManagedRuleGroups.AmazonIpReputation}),o=G.addManagedRules(o,{name:"AWSAnonymousIPList",priority:l++,...G.ManagedRuleGroups.AnonymousIpList}),o=G.addManagedRules(o,{name:"AWSCoreRuleSet",priority:l++,...G.ManagedRuleGroups.CoreRuleSet}),o=G.addManagedRules(o,{name:"AWSKnownBadInputs",priority:l++,...G.ManagedRuleGroups.KnownBadInputs}),o=G.addManagedRules(o,{name:"AWSSQLi",priority:l++,...G.ManagedRuleGroups.SqlDatabase}),n)o=G.addManagedRules(o,{name:"AWSBotControl",priority:l++,...G.ManagedRuleGroups.BotControl});if(i)o=G.setRateLimit(o,{name:"GlobalRateLimit",priority:l++,requestsPerWindow:s*5});return{webAcl:o,logicalId:c}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}class k{static createServer(e){let{slug:t,environment:a,instanceType:r="t3.micro",imageId:n="ami-0f3caa1cf4417e51b",keyName:i,securityGroupIds:s,subnetId:o,userData:c,volumeSize:l=20,volumeType:u="gp3",encrypted:m=!0}=e,p=A({slug:t,environment:a,resourceType:"ec2"}),g=f(p),h={Type:"AWS::EC2::Instance",Properties:{ImageId:n,InstanceType:r,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:a}]}};if(i)h.Properties.KeyName=i;if(s)h.Properties.SecurityGroupIds=s;if(o)h.Properties.SubnetId=o;if(c)h.Properties.UserData=C.Base64(c);return h.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:l,VolumeType:u,Encrypted:m,DeleteOnTermination:!0}}],{instance:h,logicalId:g}}static createSecurityGroup(e){let{slug:t,environment:a,vpcId:r,description:n,ingress:i=[],egress:s=[]}=e,o=A({slug:t,environment:a,resourceType:"sg"}),c=f(o),l={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:n||`Security group for ${t} ${a}`,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:a}]}};if(r)l.Properties.VpcId=r;if(i.length>0)l.Properties.SecurityGroupIngress=i.map((u)=>({IpProtocol:u.protocol,FromPort:u.fromPort,ToPort:u.toPort,CidrIp:u.cidr,SourceSecurityGroupId:u.sourceSecurityGroupId}));if(s.length>0)l.Properties.SecurityGroupEgress=s.map((u)=>({IpProtocol:u.protocol,FromPort:u.fromPort,ToPort:u.toPort,CidrIp:u.cidr,DestinationSecurityGroupId:u.sourceSecurityGroupId}));return{securityGroup:l,logicalId:c}}static createWebServerSecurityGroup(e,t,a){return k.createSecurityGroup({slug:e,environment:t,vpcId:a,description:"Security group for web servers - HTTP, HTTPS, SSH",ingress:[{protocol:"tcp",fromPort:80,toPort:80,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:443,toPort:443,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:22,toPort:22,cidr:"0.0.0.0/0"}],egress:[{protocol:"-1",fromPort:0,toPort:0,cidr:"0.0.0.0/0"}]})}static createLoadBalancer(e){let{slug:t,environment:a,scheme:r="internet-facing",subnets:n,securityGroups:i,type:s="application"}=e,o=A({slug:t,environment:a,resourceType:"alb"}),c=f(o),l={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:o,Scheme:r,Type:s,Subnets:n,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:a}]}};if(i)l.Properties.SecurityGroups=i;return{loadBalancer:l,logicalId:c}}static createTargetGroup(e){let{slug:t,environment:a,port:r,protocol:n="HTTP",vpcId:i,targetType:s="ip",healthCheckPath:o="/",healthCheckInterval:c=30,healthCheckTimeout:l=5,healthyThreshold:u=2,unhealthyThreshold:m=3}=e,p=A({slug:t,environment:a,resourceType:"tg"}),g=f(p);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:p,Port:r,Protocol:n,VpcId:i,TargetType:s,HealthCheckEnabled:!0,HealthCheckProtocol:n,HealthCheckPath:o,HealthCheckIntervalSeconds:c,HealthCheckTimeoutSeconds:l,HealthyThresholdCount:u,UnhealthyThresholdCount:m,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:a}]}},logicalId:g}}static createListener(e,t){let{port:a,protocol:r="HTTP",certificateArn:n,defaultTargetGroupArn:i}=t,s=f(`listener-${e}-${a}`),o={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:C.Ref(e),Port:a,Protocol:r,DefaultActions:[{Type:"forward",TargetGroupArn:i}]}};if(r==="HTTPS"&&n)o.Properties.Certificates=[{CertificateArn:n}],o.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:o,logicalId:s}}static createEcsCluster(e,t){let a=A({slug:e,environment:t,resourceType:"ecs-cluster"}),r=f(a);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:a,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:t}]}},logicalId:r}}static createFargateService(e){let{slug:t,environment:a,image:r,cpu:n="256",memory:i="512",desiredCount:s=1,containerPort:o=8080,environmentVariables:c={},secrets:l=[],healthCheck:u,logGroup:m,subnets:p,securityGroups:g,targetGroupArn:h}=e,{cluster:y,logicalId:b}=k.createEcsCluster(t,a),T=A({slug:t,environment:a,resourceType:"fargate"}),w=f(`${T}-execution-role`),S={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"]}},E=f(`${T}-task-role`),v={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},P=f(`${T}-task`),N={Type:"AWS::ECS::TaskDefinition",Properties:{Family:T,TaskRoleArn:C.GetAtt(E,"Arn"),ExecutionRoleArn:C.GetAtt(w,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:n,Memory:i,ContainerDefinitions:[{Name:t,Image:r,Essential:!0,PortMappings:[{ContainerPort:o,Protocol:"tcp"}],Environment:Object.entries(c).map(([L,O])=>({Name:L,Value:O})),Secrets:l.map((L)=>({Name:L.name,ValueFrom:L.valueFrom}))}],Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:a}]}};if(u)N.Properties.ContainerDefinitions[0].HealthCheck={Command:u.command,Interval:u.interval||30,Timeout:u.timeout||5,Retries:u.retries||3,StartPeriod:60};if(m)N.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":m,"awslogs-region":C.Ref("AWS::Region"),"awslogs-stream-prefix":t}};let I=f(`${T}-service`),D={Type:"AWS::ECS::Service",Properties:{ServiceName:T,Cluster:C.Ref(b),TaskDefinition:C.Ref(P),DesiredCount:s,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:p,SecurityGroups:g,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:a}]}};if(h)D.Properties.LoadBalancers=[{TargetGroupArn:h,ContainerName:t,ContainerPort:o}];return{cluster:y,taskDefinition:N,service:D,taskRole:v,executionRole:S,clusterLogicalId:b,taskDefinitionLogicalId:P,serviceLogicalId:I,taskRoleLogicalId:E,executionRoleLogicalId:w}}static createLambdaFunction(e){let{slug:t,environment:a,runtime:r,handler:n,code:i,timeout:s=30,memorySize:o=128,environmentVariables:c={},vpcConfig:l}=e,u=A({slug:t,environment:a,resourceType:"lambda"}),m=f(u),p=f(`${u}-role`),g={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}};if(l)g.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let h={Type:"AWS::Lambda::Function",Properties:{FunctionName:u,Runtime:r,Role:C.GetAtt(p,"Arn"),Handler:n,Code:{...i.s3Bucket&&{S3Bucket:i.s3Bucket},...i.s3Key&&{S3Key:i.s3Key},...i.zipFile&&{ZipFile:i.zipFile}},Timeout:s,MemorySize:o,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:a}]}};if(Object.keys(c).length>0)h.Properties.Environment={Variables:c};if(l)h.Properties.VpcConfig={SecurityGroupIds:l.securityGroupIds,SubnetIds:l.subnetIds};return{lambdaFunction:h,role:g,logicalId:m,roleLogicalId:p}}static generateNodeServerUserData(e={}){let{nodeVersion:t="20",appRepo:a,environment:r={}}=e,n=Object.entries(r).map(([i,s])=>`echo "export ${i}='${s}'" >> /etc/environment`).join(`
|
|
213
213
|
`);return`#!/bin/bash
|
|
214
214
|
# Update system
|
|
215
215
|
yum update -y
|
|
@@ -310,7 +310,7 @@ systemctl enable caddy
|
|
|
310
310
|
systemctl start caddy
|
|
311
311
|
|
|
312
312
|
echo "Bun server setup complete!"
|
|
313
|
-
`}static createLaunchConfiguration(e){let{slug:t,environment:a,imageId:r,instanceType:n,keyName:i,securityGroups:s,userData:o,volumeSize:c=20,volumeType:l="gp3",encrypted:u=!0,iamInstanceProfile:m}=e,p=A({slug:t,environment:a,resourceType:"launch-config"}),g=f(p),h={Type:"AWS::AutoScaling::LaunchConfiguration",Properties:{ImageId:r,InstanceType:n,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:c,VolumeType:l,Encrypted:u,DeleteOnTermination:!0}}]}};if(i)h.Properties.KeyName=i;if(s)h.Properties.SecurityGroups=s;if(o)h.Properties.UserData=C.Base64(o);if(m)h.Properties.IamInstanceProfile=m;return{launchConfiguration:h,logicalId:g}}static createAutoScalingGroup(e){let{slug:t,environment:a,launchConfigurationName:r,minSize:n,maxSize:i,desiredCapacity:s,vpcZoneIdentifier:o,targetGroupArns:c,healthCheckType:l="EC2",healthCheckGracePeriod:u=300,cooldown:m=300,tags:p={}}=e,g=A({slug:t,environment:a,resourceType:"asg"}),h=f(g),y={Type:"AWS::AutoScaling::AutoScalingGroup",Properties:{AutoScalingGroupName:g,LaunchConfigurationName:r,MinSize:n,MaxSize:i,HealthCheckType:l,HealthCheckGracePeriod:u,Cooldown:m,Tags:[{Key:"Name",Value:g,PropagateAtLaunch:!0},{Key:"Environment",Value:a,PropagateAtLaunch:!0},...Object.entries(p).map(([b,T])=>({Key:b,Value:T,PropagateAtLaunch:!0}))]}};if(s!==void 0)y.Properties.DesiredCapacity=s;if(o)y.Properties.VPCZoneIdentifier=o;if(c)y.Properties.TargetGroupARNs=c;return y.UpdatePolicy={AutoScalingRollingUpdate:{MaxBatchSize:1,MinInstancesInService:Math.max(0,n-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:y,logicalId:h}}static createScalingPolicy(e){let{slug:t,environment:a,autoScalingGroupName:r,policyType:n="TargetTrackingScaling",targetValue:i=70,predefinedMetricType:s="ASGAverageCPUUtilization"}=e,o=A({slug:t,environment:a,resourceType:"scaling-policy"}),c=f(o),l={Type:"AWS::AutoScaling::ScalingPolicy",Properties:{AutoScalingGroupName:r,PolicyType:n}};if(n==="TargetTrackingScaling")l.Properties.TargetTrackingConfiguration={PredefinedMetricSpecification:{PredefinedMetricType:s},TargetValue:i};return{scalingPolicy:l,logicalId:c}}static AutoScaling={smallWebServer:(e,t,a,r,n)=>
|
|
313
|
+
`}static createLaunchConfiguration(e){let{slug:t,environment:a,imageId:r,instanceType:n,keyName:i,securityGroups:s,userData:o,volumeSize:c=20,volumeType:l="gp3",encrypted:u=!0,iamInstanceProfile:m}=e,p=A({slug:t,environment:a,resourceType:"launch-config"}),g=f(p),h={Type:"AWS::AutoScaling::LaunchConfiguration",Properties:{ImageId:r,InstanceType:n,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:c,VolumeType:l,Encrypted:u,DeleteOnTermination:!0}}]}};if(i)h.Properties.KeyName=i;if(s)h.Properties.SecurityGroups=s;if(o)h.Properties.UserData=C.Base64(o);if(m)h.Properties.IamInstanceProfile=m;return{launchConfiguration:h,logicalId:g}}static createAutoScalingGroup(e){let{slug:t,environment:a,launchConfigurationName:r,minSize:n,maxSize:i,desiredCapacity:s,vpcZoneIdentifier:o,targetGroupArns:c,healthCheckType:l="EC2",healthCheckGracePeriod:u=300,cooldown:m=300,tags:p={}}=e,g=A({slug:t,environment:a,resourceType:"asg"}),h=f(g),y={Type:"AWS::AutoScaling::AutoScalingGroup",Properties:{AutoScalingGroupName:g,LaunchConfigurationName:r,MinSize:n,MaxSize:i,HealthCheckType:l,HealthCheckGracePeriod:u,Cooldown:m,Tags:[{Key:"Name",Value:g,PropagateAtLaunch:!0},{Key:"Environment",Value:a,PropagateAtLaunch:!0},...Object.entries(p).map(([b,T])=>({Key:b,Value:T,PropagateAtLaunch:!0}))]}};if(s!==void 0)y.Properties.DesiredCapacity=s;if(o)y.Properties.VPCZoneIdentifier=o;if(c)y.Properties.TargetGroupARNs=c;return y.UpdatePolicy={AutoScalingRollingUpdate:{MaxBatchSize:1,MinInstancesInService:Math.max(0,n-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:y,logicalId:h}}static createScalingPolicy(e){let{slug:t,environment:a,autoScalingGroupName:r,policyType:n="TargetTrackingScaling",targetValue:i=70,predefinedMetricType:s="ASGAverageCPUUtilization"}=e,o=A({slug:t,environment:a,resourceType:"scaling-policy"}),c=f(o),l={Type:"AWS::AutoScaling::ScalingPolicy",Properties:{AutoScalingGroupName:r,PolicyType:n}};if(n==="TargetTrackingScaling")l.Properties.TargetTrackingConfiguration={PredefinedMetricSpecification:{PredefinedMetricType:s},TargetValue:i};return{scalingPolicy:l,logicalId:c}}static AutoScaling={smallWebServer:(e,t,a,r,n)=>k.createAutoScalingGroup({slug:e,environment:t,launchConfigurationName:a,minSize:2,maxSize:4,desiredCapacity:2,vpcZoneIdentifier:r,targetGroupArns:n,healthCheckType:n?"ELB":"EC2",healthCheckGracePeriod:300}),mediumWebServer:(e,t,a,r,n)=>k.createAutoScalingGroup({slug:e,environment:t,launchConfigurationName:a,minSize:3,maxSize:10,desiredCapacity:3,vpcZoneIdentifier:r,targetGroupArns:n,healthCheckType:n?"ELB":"EC2",healthCheckGracePeriod:300}),largeWebServer:(e,t,a,r,n)=>k.createAutoScalingGroup({slug:e,environment:t,launchConfigurationName:a,minSize:5,maxSize:20,desiredCapacity:5,vpcZoneIdentifier:r,targetGroupArns:n,healthCheckType:n?"ELB":"EC2",healthCheckGracePeriod:300}),cpuScaling:(e,t,a,r=70)=>k.createScalingPolicy({slug:e,environment:t,autoScalingGroupName:a,policyType:"TargetTrackingScaling",predefinedMetricType:"ASGAverageCPUUtilization",targetValue:r}),requestCountScaling:(e,t,a,r=1000)=>k.createScalingPolicy({slug:e,environment:t,autoScalingGroupName:a,policyType:"TargetTrackingScaling",predefinedMetricType:"ALBRequestCountPerTarget",targetValue:r})};static Secrets={fromSecretsManager:(e)=>Object.entries(e).map(([t,a])=>({name:t,valueFrom:a})),fromJsonSecret:(e,t)=>`${e}:${t}::`,fromSecretVersion:(e,t)=>`${e}::${t}:`,fromSecretVersionStage:(e,t)=>`${e}:::${t}`,createAccessPolicy:(e)=>({PolicyName:"SecretsManagerAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],Resource:e}]}}),createKmsPolicy:(e)=>({PolicyName:"KMSDecryptAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["kms:Decrypt"],Resource:e}]}}),buildSecretArn:(e)=>`arn:aws:secretsmanager:${e.region}:${e.accountId}:secret:${e.secretName}`,buildSecretArnPattern:(e)=>{let t=e.region||"*",a=e.accountId||"*";return`arn:aws:secretsmanager:${t}:${a}:secret:${e.secretNamePrefix}*`},commonAppSecrets:(e)=>({DATABASE_URL:`${e}/database-url`,DATABASE_PASSWORD:`${e}/database-password`,REDIS_URL:`${e}/redis-url`,REDIS_PASSWORD:`${e}/redis-password`,API_KEY:`${e}/api-key`,JWT_SECRET:`${e}/jwt-secret`,ENCRYPTION_KEY:`${e}/encryption-key`,AWS_ACCESS_KEY_ID:`${e}/aws-access-key-id`,AWS_SECRET_ACCESS_KEY:`${e}/aws-secret-access-key`,MAIL_PASSWORD:`${e}/mail-password`,STRIPE_SECRET_KEY:`${e}/stripe-secret-key`,STRIPE_WEBHOOK_SECRET:`${e}/stripe-webhook-secret`})};static createFargateServiceWithSecrets(e){let{secretArns:t=[],kmsKeyArns:a=[],...r}=e,n=k.createFargateService(r);if(t.length>0){if(!n.executionRole.Properties.Policies)n.executionRole.Properties.Policies=[];if(n.executionRole.Properties.Policies.push(k.Secrets.createAccessPolicy(t)),a.length>0)n.executionRole.Properties.Policies.push(k.Secrets.createKmsPolicy(a))}return n}static generateSecretReferences(e){return e.secrets.map((t)=>{let a=`arn:aws:secretsmanager:${e.region}:${e.accountId}:secret:${e.secretPrefix}/${t}`;return{name:t.toUpperCase().replace(/-/g,"_"),valueFrom:a}})}static EnvSecrets={database:(e)=>[{name:"DB_HOST",valueFrom:`${e}:host::`},{name:"DB_PORT",valueFrom:`${e}:port::`},{name:"DB_USERNAME",valueFrom:`${e}:username::`},{name:"DB_PASSWORD",valueFrom:`${e}:password::`},{name:"DB_NAME",valueFrom:`${e}:dbname::`}],redis:(e)=>[{name:"REDIS_HOST",valueFrom:`${e}:host::`},{name:"REDIS_PORT",valueFrom:`${e}:port::`},{name:"REDIS_PASSWORD",valueFrom:`${e}:password::`}],apiCredentials:(e)=>[{name:"API_KEY",valueFrom:`${e}:apiKey::`},{name:"API_SECRET",valueFrom:`${e}:apiSecret::`}],mail:(e)=>[{name:"MAIL_HOST",valueFrom:`${e}:host::`},{name:"MAIL_PORT",valueFrom:`${e}:port::`},{name:"MAIL_USERNAME",valueFrom:`${e}:username::`},{name:"MAIL_PASSWORD",valueFrom:`${e}:password::`}],awsCredentials:(e)=>[{name:"AWS_ACCESS_KEY_ID",valueFrom:`${e}:accessKeyId::`},{name:"AWS_SECRET_ACCESS_KEY",valueFrom:`${e}:secretAccessKey::`}]};static createJumpBox(e){let{slug:t,environment:a,vpcId:r,subnetId:n,keyName:i,instanceType:s="t3.micro",imageId:o="ami-0f3caa1cf4417e51b",allowedCidrs:c=["0.0.0.0/0"],mountEfs:l}=e,u=A({slug:t,environment:a,resourceType:"jumpbox"}),m=f(`${u}-sg`),p={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:`${u}-sg`,GroupDescription:`Security group for ${u} JumpBox SSH access`,VpcId:r,SecurityGroupIngress:c.map((v)=>({IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:v,Description:`SSH access from ${v}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound traffic"}],Tags:[{Key:"Name",Value:`${u}-sg`},{Key:"Environment",Value:a}]}},g=f(`${u}-role`),h={Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ec2.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"],Policies:l?[{PolicyName:"EFSAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess"],Resource:"*"}]}}]:void 0}},y=f(`${u}-profile`),b={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:`${u}-profile`,Roles:[C.Ref(g)]}},T=`#!/bin/bash
|
|
314
314
|
yum update -y
|
|
315
315
|
yum install -y amazon-efs-utils nfs-utils jq curl wget htop
|
|
316
316
|
`;if(l){let v=l.mountPath||"/mnt/efs";T+=`
|
|
@@ -318,7 +318,7 @@ yum install -y amazon-efs-utils nfs-utils jq curl wget htop
|
|
|
318
318
|
mkdir -p ${v}
|
|
319
319
|
mount -t efs ${l.fileSystemId}:/ ${v}
|
|
320
320
|
echo "${l.fileSystemId}:/ ${v} efs defaults,_netdev 0 0" >> /etc/fstab
|
|
321
|
-
`}let w=f(u),S={Type:"AWS::EC2::Instance",DependsOn:[y],Properties:{ImageId:o,InstanceType:s,KeyName:i,SubnetId:n,SecurityGroupIds:[C.Ref(m)],IamInstanceProfile:C.Ref(y),UserData:C.Base64(T),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:a},{Key:"Purpose",Value:"JumpBox/Bastion"}]}},E={[m]:p,[g]:h,[y]:b,[w]:S};return{instance:S,securityGroup:p,instanceProfile:b,instanceRole:h,instanceLogicalId:w,securityGroupLogicalId:m,instanceProfileLogicalId:y,instanceRoleLogicalId:g,resources:E}}static JumpBox={withEfsMount:(e)=>
|
|
321
|
+
`}let w=f(u),S={Type:"AWS::EC2::Instance",DependsOn:[y],Properties:{ImageId:o,InstanceType:s,KeyName:i,SubnetId:n,SecurityGroupIds:[C.Ref(m)],IamInstanceProfile:C.Ref(y),UserData:C.Base64(T),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:a},{Key:"Purpose",Value:"JumpBox/Bastion"}]}},E={[m]:p,[g]:h,[y]:b,[w]:S};return{instance:S,securityGroup:p,instanceProfile:b,instanceRole:h,instanceLogicalId:w,securityGroupLogicalId:m,instanceProfileLogicalId:y,instanceRoleLogicalId:g,resources:E}}static JumpBox={withEfsMount:(e)=>k.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)=>k.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,instanceType:"t3.nano",allowedCidrs:e.allowedCidrs}),withDatabaseTools:(e)=>{let t=k.createJumpBox({slug:e.slug,environment:e.environment,vpcId:e.vpcId,subnetId:e.subnetId,keyName:e.keyName,allowedCidrs:e.allowedCidrs}),a=`#!/bin/bash
|
|
322
322
|
yum update -y
|
|
323
323
|
yum install -y amazon-efs-utils nfs-utils jq curl wget htop
|
|
324
324
|
|
|
@@ -346,7 +346,7 @@ yum install -y mysql
|
|
|
346
346
|
yum install -y redis
|
|
347
347
|
|
|
348
348
|
echo "Database tools installed!"
|
|
349
|
-
`),t},commonCidrs:{any:["0.0.0.0/0"],privateOnly:["10.0.0.0/8","172.16.0.0/12","192.168.0.0/16"]}};static InstanceSize={toInstanceType:(e,t="t3")
|
|
349
|
+
`),t},commonCidrs:{any:["0.0.0.0/0"],privateOnly:["10.0.0.0/8","172.16.0.0/12","192.168.0.0/16"]}};static InstanceSize={toInstanceType:(e,t="t3")=>`${t}.${e}`,specs:{nano:{vcpu:2,memory:0.5,instanceType:"t3.nano"},micro:{vcpu:2,memory:1,instanceType:"t3.micro"},small:{vcpu:2,memory:2,instanceType:"t3.small"},medium:{vcpu:2,memory:4,instanceType:"t3.medium"},large:{vcpu:2,memory:8,instanceType:"t3.large"},xlarge:{vcpu:4,memory:16,instanceType:"t3.xlarge"},"2xlarge":{vcpu:8,memory:32,instanceType:"t3.2xlarge"}},toFargateSpecs:(e)=>{let t={nano:{cpu:"256",memory:"512"},micro:{cpu:"256",memory:"1024"},small:{cpu:"512",memory:"1024"},medium:{cpu:"1024",memory:"2048"},large:{cpu:"2048",memory:"4096"},xlarge:{cpu:"4096",memory:"8192"},"2xlarge":{cpu:"4096",memory:"16384"}};return t[e]||t.medium},toLambdaMemory:(e)=>({nano:128,micro:256,small:512,medium:1024,large:2048,xlarge:4096,"2xlarge":8192})[e]||1024,presets:{webServer:"t3.small",apiServer:"t3.medium",worker:"t3.medium",database:"r6i.large",cache:"r6i.medium",compute:"c6i.large",general:"m6i.medium"}};static DiskConfig={create:(e)=>{let{size:t,type:a="ssd",encrypted:r=!0,iops:n,throughput:i,deleteOnTermination:s=!0}=e,o={standard:"gp2",ssd:"gp3",premium:"io2",gp2:"gp2",gp3:"gp3",io1:"io1",io2:"io2"}[a]||"gp3",c={VolumeSize:t,VolumeType:o,Encrypted:r,DeleteOnTermination:s};if((o==="io1"||o==="io2"||o==="gp3")&&n)c.Iops=n;if(o==="gp3"&&i)c.Throughput=i;return c},presets:{standard:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0},large:{VolumeSize:100,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0},highPerformance:{VolumeSize:50,VolumeType:"io2",Iops:3000,Encrypted:!0,DeleteOnTermination:!0},database:{VolumeSize:100,VolumeType:"io2",Iops:1e4,Encrypted:!0,DeleteOnTermination:!1}}};static SpotConfig={create:(e)=>{let{maxPrice:t,spotInstanceType:a="one-time",interruptionBehavior:r="terminate",blockDurationMinutes:n}=e,i={SpotInstanceType:a,InstanceInterruptionBehavior:r};if(t)i.MaxPrice=t;if(n)i.BlockDurationMinutes=n;return{SpotOptions:i}},presets:{standard:{spotInstanceType:"one-time",interruptionBehavior:"terminate"},persistent:{spotInstanceType:"persistent",interruptionBehavior:"stop"},costOptimized:{maxPrice:"0.05",spotInstanceType:"one-time",interruptionBehavior:"terminate"}}};static MixedInstances={create:(e)=>{let{instanceTypes:t,baseCapacity:a=0,onDemandPercentage:r=20,spotAllocationStrategy:n="capacity-optimized",spotMaxPrice:i}=e,s={OnDemandBaseCapacity:a,OnDemandPercentageAboveBaseCapacity:r,SpotAllocationStrategy:n};if(i)s.SpotMaxPrice=i;let o=t.map(({size:c,weight:l})=>{let u={InstanceType:k.InstanceSize.toInstanceType(c)};if(l)u.WeightedCapacity=String(l);return u});return{MixedInstancesPolicy:{InstancesDistribution:s,LaunchTemplate:{Overrides:o}}}},presets:{costOptimized:{baseCapacity:0,onDemandPercentage:20,spotAllocationStrategy:"lowest-price",instanceTypes:[{size:"small",weight:1},{size:"medium",weight:2}]},balanced:{baseCapacity:1,onDemandPercentage:50,spotAllocationStrategy:"capacity-optimized",instanceTypes:[{size:"medium",weight:1},{size:"large",weight:2}]},highAvailability:{baseCapacity:2,onDemandPercentage:80,spotAllocationStrategy:"capacity-optimized-prioritized",instanceTypes:[{size:"medium",weight:1}]}}};static AutoScalingConfig={create:(e)=>{let{min:t,max:a,desired:r=t,scaleUpThreshold:n=70,scaleDownThreshold:i=30,cooldownSeconds:s=300,targetMetric:o="cpu"}=e,c={cpu:"ASGAverageCPUUtilization",memory:"ASGAverageMemoryUtilization",requests:"ALBRequestCountPerTarget"};return{minSize:t,maxSize:a,desiredCapacity:r,scalingPolicies:[{policyType:"TargetTrackingScaling",targetValue:n,predefinedMetricType:c[o]||c.cpu,scaleInCooldown:s,scaleOutCooldown:s}]}},forEcs:(e)=>{let{min:t,max:a,cpuTarget:r=70,memoryTarget:n}=e,i=[{predefinedMetricType:"ECSServiceAverageCPUUtilization",targetValue:r}];if(n)i.push({predefinedMetricType:"ECSServiceAverageMemoryUtilization",targetValue:n});return{minCapacity:t,maxCapacity:a,targetTrackingPolicies:i}},presets:{small:{min:1,max:3,scaleUpThreshold:70,scaleDownThreshold:30},medium:{min:2,max:10,scaleUpThreshold:70,scaleDownThreshold:30},large:{min:3,max:50,scaleUpThreshold:60,scaleDownThreshold:40},highAvailability:{min:2,max:20,scaleUpThreshold:60,scaleDownThreshold:30}}};static LoadBalancerConfig={healthCheck:(e)=>{let{path:t="/",interval:a=30,timeout:r=5,healthyThreshold:n=2,unhealthyThreshold:i=5,protocol:s="HTTP"}=e,o={HealthCheckIntervalSeconds:a,HealthCheckTimeoutSeconds:r,HealthyThresholdCount:n,UnhealthyThresholdCount:i};if(s!=="TCP")o.HealthCheckPath=t,o.HealthCheckProtocol=s;return o},presets:{standard:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:5},fast:{path:"/health",interval:10,timeout:3,healthyThreshold:2,unhealthyThreshold:2},relaxed:{path:"/health",interval:60,timeout:30,healthyThreshold:2,unhealthyThreshold:10}}};static SslConfig={httpsListener:(e)=>{let{certificateArn:t,targetGroupArn:a,port:r=443,sslPolicy:n="ELBSecurityPolicy-TLS13-1-2-2021-06"}=e;return{Port:r,Protocol:"HTTPS",Certificates:[{CertificateArn:t}],SslPolicy:n,DefaultActions:[{Type:"forward",TargetGroupArn:a}]}},httpRedirectListener:(e=80)=>({Port:e,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}),policies:{tls13:"ELBSecurityPolicy-TLS13-1-2-2021-06",tls12:"ELBSecurityPolicy-TLS-1-2-Ext-2018-06",tls11:"ELBSecurityPolicy-TLS-1-1-2017-01",fips:"ELBSecurityPolicy-TLS-1-2-Ext-FIPS-2022-05"}};static FunctionConfig={create:(e)=>{let{handler:t,runtime:a="nodejs20.x",timeout:r=30,memorySize:n=256,environmentVariables:i,reservedConcurrency:s}=e,o={Handler:t,Runtime:a,Timeout:r,MemorySize:n};if(i)o.Environment={Variables:i};if(s)o.ReservedConcurrentExecutions=s;return o},runtimes:{nodejs20:"nodejs20.x",nodejs18:"nodejs18.x",python312:"python3.12",python311:"python3.11",java21:"java21",java17:"java17",go:"provided.al2023",rust:"provided.al2023",bun:"provided.al2023"},presets:{api:{runtime:"nodejs20.x",timeout:30,memorySize:256},worker:{runtime:"nodejs20.x",timeout:300,memorySize:512},cron:{runtime:"nodejs20.x",timeout:900,memorySize:1024},dataProcessing:{runtime:"nodejs20.x",timeout:900,memorySize:3008}}};static UserData={generateAppServerScript:(e)=>{let{runtime:t="bun",runtimeVersion:a="latest",webServer:r="nginx",processManager:n="systemd",enableSsl:i=!0,sslEmail:s="admin@example.com",domain:o,appPort:c=3000,installDatabaseClients:l=!1,installRedis:u=!1,extraPackages:m=[]}=e,p=`#!/bin/bash
|
|
350
350
|
set -e
|
|
351
351
|
|
|
352
352
|
# Update system
|
|
@@ -604,7 +604,7 @@ ufw default allow outgoing
|
|
|
604
604
|
${e.map((t)=>`ufw allow ${t}`).join(`
|
|
605
605
|
`)}
|
|
606
606
|
ufw --force enable
|
|
607
|
-
`},Presets:{bunWithNginx:(e,t=3000)=>k.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:e,appPort:t,enableSsl:!0}),bunWithCaddy:(e,t=3000)=>k.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:e,appPort:t,enableSsl:!1}),nodeWithPm2:(e,t=3000)=>k.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:e,appPort:t,enableSsl:!0}),worker:(e="bun")=>k.UserData.generateAppServerScript({runtime:e,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(e){let{slug:t,environment:a,domain:r,instanceLogicalId:n}=e,i=A({slug:t,environment:a,resourceType:"eip"}),s=f(i),o={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:a},...r?[{Key:"Domain",Value:r}]:[]]}},c={[s]:o},l,u;if(n)u=f(`${i}-assoc`),l={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:C.GetAtt(s,"AllocationId"),InstanceId:C.Ref(n)}},c[u]=l;return{eip:o,eipAssociation:l,eipLogicalId:s,associationLogicalId:u,resources:c}}static createServerModeStack(e){let{slug:t,environment:a,vpcId:r,subnetId:n,instanceType:i="t3.small",imageId:s="ami-0f3caa1cf4417e51b",keyName:o,domain:c,userData:l,allowedPorts:u=[22,80,443],volumeSize:m=20,volumeType:p="gp3"}=e,g={},h=A({slug:t,environment:a,resourceType:"server-sg"}),y=f(h),b={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:h,GroupDescription:`Security group for ${t} server`,VpcId:r,SecurityGroupIngress:u.map((
|
|
607
|
+
`},Presets:{bunWithNginx:(e,t=3000)=>k.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:e,appPort:t,enableSsl:!0}),bunWithCaddy:(e,t=3000)=>k.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:e,appPort:t,enableSsl:!1}),nodeWithPm2:(e,t=3000)=>k.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:e,appPort:t,enableSsl:!0}),worker:(e="bun")=>k.UserData.generateAppServerScript({runtime:e,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(e){let{slug:t,environment:a,domain:r,instanceLogicalId:n}=e,i=A({slug:t,environment:a,resourceType:"eip"}),s=f(i),o={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:a},...r?[{Key:"Domain",Value:r}]:[]]}},c={[s]:o},l,u;if(n)u=f(`${i}-assoc`),l={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:C.GetAtt(s,"AllocationId"),InstanceId:C.Ref(n)}},c[u]=l;return{eip:o,eipAssociation:l,eipLogicalId:s,associationLogicalId:u,resources:c}}static createServerModeStack(e){let{slug:t,environment:a,vpcId:r,subnetId:n,instanceType:i="t3.small",imageId:s="ami-0f3caa1cf4417e51b",keyName:o,domain:c,userData:l,allowedPorts:u=[22,80,443],volumeSize:m=20,volumeType:p="gp3"}=e,g={},h=A({slug:t,environment:a,resourceType:"server-sg"}),y=f(h),b={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:h,GroupDescription:`Security group for ${t} server`,VpcId:r,SecurityGroupIngress:u.map((F)=>({IpProtocol:"tcp",FromPort:F,ToPort:F,CidrIp:"0.0.0.0/0",Description:`Port ${F}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:a}]}};g[y]=b;let T=A({slug:t,environment:a,resourceType:"server-role"}),w=f(T),S={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:"*"}]}}]}};g[w]=S;let E=A({slug:t,environment:a,resourceType:"server-profile"}),v=f(E),P={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:E,Roles:[C.Ref(w)]}};g[v]=P;let N=A({slug:t,environment:a,resourceType:"server"}),I=f(N),D={Type:"AWS::EC2::Instance",DependsOn:[v],Properties:{ImageId:s,InstanceType:i,KeyName:o,SubnetId:n,SecurityGroupIds:[C.Ref(y)],IamInstanceProfile:C.Ref(v),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:N},{Key:"Environment",Value:a},...c?[{Key:"Domain",Value:c}]:[]]}};if(l)D.Properties.UserData=C.Base64(l);g[I]=D;let{eip:L,eipAssociation:O,eipLogicalId:ce,associationLogicalId:j,resources:ae}=k.createElasticIp({slug:t,environment:a,domain:c,instanceLogicalId:I});return Object.assign(g,ae),{instance:D,securityGroup:b,eip:L,eipAssociation:O,instanceRole:S,instanceProfile:P,resources:g,outputs:{instanceLogicalId:I,securityGroupLogicalId:y,eipLogicalId:ce,associationLogicalId:j,roleLogicalId:w,profileLogicalId:v}}}static ServerMode={webServer:(e)=>{let t=k.UserData.generateAppServerScript({runtime:e.runtime||"bun",webServer:e.webServer||"nginx",domain:e.domain,enableSsl:!0});return k.createServerModeStack({...e,userData:t,instanceType:"t3.small",allowedPorts:[22,80,443]})},workerServer:(e)=>{let t=k.UserData.generateAppServerScript({runtime:e.runtime||"bun",webServer:"none",installRedis:e.installRedis});return k.createServerModeStack({...e,userData:t,instanceType:"t3.medium",allowedPorts:[22]})},cacheServer:(e)=>k.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]})}}
|
|
615
|
+
`,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class B{static createVpc(e){let{slug:t,environment:a,cidr:r="10.0.0.0/16",enableDnsHostnames:n=!0,enableDnsSupport:i=!0}=e,s=A({slug:t,environment:a,resourceType:"vpc"}),o=f(s);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:r,EnableDnsHostnames:n,EnableDnsSupport:i,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:a}]}},logicalId:o}}static createSubnet(e){let{slug:t,environment:a,vpcId:r,type:n,cidr:i,availabilityZone:s,mapPublicIp:o=n==="public"}=e,c=A({slug:t,environment:a,resourceType:`subnet-${n}`}),l=f(`${c}-${s}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:r,CidrBlock:i,AvailabilityZone:s,MapPublicIpOnLaunch:o,Tags:[{Key:"Name",Value:`${c}-${s}`},{Key:"Environment",Value:a},{Key:"Type",Value:n}]}},logicalId:l}}static createInternetGateway(e,t){let a=A({slug:e,environment:t,resourceType:"igw"}),r=f(a);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:t}]}},logicalId:r}}static attachInternetGateway(e,t){let a=f(`${e}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:C.Ref(e),InternetGatewayId:C.Ref(t)}},logicalId:a}}static createEip(e,t){let a=A({slug:e,environment:t,resourceType:"eip"}),r=f(a);return{eip:{Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:t}]}},logicalId:r}}static createNatGateway(e,t){let{slug:a,environment:r,subnetId:n}=e,i=A({slug:a,environment:r,resourceType:"nat"}),s=f(i);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:C.GetAtt(t,"AllocationId"),SubnetId:n,Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:r},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:s}}static createRouteTable(e,t,a,r){let n=A({slug:e,environment:t,resourceType:`rt-${r}`}),i=f(n);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:C.Ref(a),Tags:[{Key:"Name",Value:n},{Key:"Environment",Value:t},{Key:"Type",Value:r}]}},logicalId:i}}static createRoute(e,t,a){let r=f(`${e}-route-${a.type}`),n={Type:"AWS::EC2::Route",Properties:{RouteTableId:C.Ref(e),DestinationCidrBlock:t}};if(a.type==="igw")n.Properties.GatewayId=C.Ref(a.logicalId);else if(a.type==="nat")n.Properties.NatGatewayId=C.Ref(a.logicalId);else if(a.type==="instance")n.Properties.InstanceId=C.Ref(a.logicalId);return{route:n,logicalId:r}}static associateSubnetWithRouteTable(e,t){let a=f(`${e}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:C.Ref(e),RouteTableId:C.Ref(t)}},logicalId:a}}static enableFlowLogs(e){let{slug:t,environment:a,resourceId:r,resourceType:n,trafficType:i="ALL",logGroupName:s}=e,o=A({slug:t,environment:a,resourceType:"flowlog"}),c=f(o);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:n,ResourceIds:[r],TrafficType:i,LogDestinationType:"cloud-watch-logs",LogGroupName:s||`/aws/vpc/${t}-${a}`,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:a}]}},logicalId:c}}static calculateSubnetCidrs(e,t,a=3){let[r,n]=e.split("/"),i=Number.parseInt(n,10),s=Math.ceil(Math.log2(t*a)),o=i+s;if(o>28)throw Error("VPC CIDR is too small to accommodate requested subnets");let[c,l,u,m]=r.split(".").map(Number),p=(c<<24)+(l<<16)+(u<<8)+m,g=2**(32-o),h=[];for(let y=0;y<t*a;y++){let b=p+y*g,T=[b>>>24&255,b>>>16&255,b>>>8&255,b&255].join(".");h.push(`${T}/${o}`)}return h}static getAvailabilityZones(e,t){return["a","b","c","d","e","f"].slice(0,t).map((a)=>`${e}${a}`)}static createMultiAzNetwork(e){let{slug:t,environment:a,region:r,cidr:n="10.0.0.0/16",zones:i=3,enableNatGateway:s=!1,singleNatGateway:o=!1,enableFlowLogs:c=!1}=e,l={},u=[],m=[],p=[],{vpc:g,logicalId:h}=B.createVpc({slug:t,environment:a,cidr:n});l[h]=g;let{internetGateway:y,logicalId:b}=B.createInternetGateway(t,a);l[b]=y;let{attachment:T,logicalId:w}=B.attachInternetGateway(h,b);l[w]=T;let{routeTable:S,logicalId:E}=B.createRouteTable(t,a,h,"public");l[E]=S;let{route:v,logicalId:P}=B.createRoute(E,"0.0.0.0/0",{type:"igw",logicalId:b});v.DependsOn=w,l[P]=v;let N=B.calculateSubnetCidrs(n,i,2),I=B.getAvailabilityZones(r,i),D=[];for(let L=0;L<i;L++){let O=I[L],ce=N[L*2],j=N[L*2+1],{subnet:ae,logicalId:F}=B.createSubnet({slug:t,environment:a,vpcId:C.Ref(h),type:"public",cidr:ce,availabilityZone:O});l[F]=ae,u.push(F);let{association:we,logicalId:Ge}=B.associateSubnetWithRouteTable(F,E);l[Ge]=we;let{subnet:Nt,logicalId:le}=B.createSubnet({slug:t,environment:a,vpcId:C.Ref(h),type:"private",cidr:j,availabilityZone:O});if(l[le]=Nt,m.push(le),s&&(!o||L===0)){let{eip:re,logicalId:ue}=B.createEip(`${t}-${O}`,a);l[ue]=re;let{natGateway:Ee,logicalId:de}=B.createNatGateway({slug:`${t}-${O}`,environment:a,subnetId:C.Ref(F)},ue);Ee.DependsOn=w,l[de]=Ee,p.push(de);let{routeTable:Se,logicalId:$e}=B.createRouteTable(`${t}-${O}`,a,h,"private");l[$e]=Se,D.push($e);let{route:Fe,logicalId:R}=B.createRoute($e,"0.0.0.0/0",{type:"nat",logicalId:de});l[R]=Fe;let{association:x,logicalId:M}=B.associateSubnetWithRouteTable(le,$e);l[M]=x}else if(s&&o&&L>0){let{association:re,logicalId:ue}=B.associateSubnetWithRouteTable(le,D[0]);l[ue]=re}else{let{routeTable:re,logicalId:ue}=B.createRouteTable(`${t}-${O}-isolated`,a,h,"private");l[ue]=re;let{association:Ee,logicalId:de}=B.associateSubnetWithRouteTable(le,ue);l[de]=Ee}}if(c){let{flowLog:L,logicalId:O}=B.enableFlowLogs({slug:t,environment:a,resourceId:C.Ref(h),resourceType:"VPC"});l[O]=L}return{resources:l,outputs:{vpcId:h,publicSubnetIds:u,privateSubnetIds:m,natGatewayIds:p.length>0?p:void 0}}}static NatGatewayCostWarning=`
|
|
616
616
|
⚠️ NAT Gateway Cost Warning:
|
|
617
617
|
- Each NAT Gateway costs approximately $32-45/month (hourly charges)
|
|
618
618
|
- Data processing charges: $0.045/GB processed
|
|
@@ -1166,7 +1166,7 @@ else if (encoding === 'quoted-printable') {
|
|
|
1166
1166
|
|
|
1167
1167
|
return content;
|
|
1168
1168
|
}
|
|
1169
|
-
`}}var
|
|
1169
|
+
`}}var ui={};De(ui,{default:()=>di,handler:()=>ja});var ja=`
|
|
1170
1170
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1171
1171
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1172
1172
|
|
|
@@ -1273,7 +1273,7 @@ catch (error) {
|
|
|
1273
1273
|
};
|
|
1274
1274
|
}
|
|
1275
1275
|
};
|
|
1276
|
-
`,
|
|
1276
|
+
`,di=`
|
|
1277
1277
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1278
1278
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1279
1279
|
|
|
@@ -1380,7 +1380,7 @@ catch (error) {
|
|
|
1380
1380
|
};
|
|
1381
1381
|
}
|
|
1382
1382
|
};
|
|
1383
|
-
`,
|
|
1383
|
+
`,mi=`
|
|
1384
1384
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1385
1385
|
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1386
1386
|
|
|
@@ -1487,7 +1487,7 @@ catch (error) {
|
|
|
1487
1487
|
};
|
|
1488
1488
|
}
|
|
1489
1489
|
};
|
|
1490
|
-
`,
|
|
1490
|
+
`,pi=`
|
|
1491
1491
|
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
1492
1492
|
const { TranscribeClient, StartTranscriptionJobCommand, GetTranscriptionJobCommand } = require('@aws-sdk/client-transcribe');
|
|
1493
1493
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
@@ -1658,7 +1658,7 @@ catch (error) {
|
|
|
1658
1658
|
|
|
1659
1659
|
return { statusCode: 200, body: 'OK' };
|
|
1660
1660
|
};
|
|
1661
|
-
`;class pe{static LambdaCode={incomingCall:ja,voicemail:mi,missedCall:di};static createConnectInstance(e){let{slug:t,environment:a,instanceAlias:r,inboundCallsEnabled:n=!0,outboundCallsEnabled:i=!0}=e;return{[`${t}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:r,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:n,OutboundCalls:i,ContactflowLogs:!0,ContactLens:!0,AutoResolveBestVoices:!0,UseCustomTTSVoices:!1,EarlyMedia:!0}}}}}static createHoursOfOperation(e){return{[`${e.slug}HoursOfOperation`]:{Type:"AWS::Connect::HoursOfOperation",Properties:{InstanceArn:e.instanceArn,Name:e.name,TimeZone:e.timezone,Config:e.schedule.map((t)=>({Day:t.day,StartTime:{Hours:t.startHour,Minutes:t.startMinute},EndTime:{Hours:t.endHour,Minutes:t.endMinute}}))}}}}static createQueue(e){return{[`${e.slug}Queue`]:{Type:"AWS::Connect::Queue",Properties:{InstanceArn:e.instanceArn,Name:e.name,HoursOfOperationArn:e.hoursOfOperationArn,MaxContacts:e.maxContacts||10}}}}static createContactFlow(e){return{[`${e.slug}ContactFlow`]:{Type:"AWS::Connect::ContactFlow",Properties:{InstanceArn:e.instanceArn,Name:e.name,Type:e.type,Content:e.content}}}}static createBasicIvrFlow(e){let t={Version:"2019-10-30",StartAction:"greeting",Actions:[{Identifier:"greeting",Type:"MessageParticipant",Parameters:{Text:e.greeting},Transitions:{NextAction:"transfer_to_queue",Errors:[{NextAction:"disconnect"}]}},{Identifier:"transfer_to_queue",Type:"TransferToQueue",Parameters:{QueueId:e.queueArn},Transitions:{NextAction:e.voicemailLambdaArn?"voicemail":"disconnect",Errors:[{NextAction:"disconnect"}]}},...e.voicemailLambdaArn?[{Identifier:"voicemail",Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:e.voicemailLambdaArn},Transitions:{NextAction:"disconnect",Errors:[{NextAction:"disconnect"}]}}]:[],{Identifier:"disconnect",Type:"DisconnectParticipant",Parameters:{},Transitions:{}}]};return JSON.stringify(t)}static createPhoneLambdaRole(e){return{[`${e.slug}PhoneLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.slug}-phone-lambda-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"PhoneLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"}]}}]}}}}static createIncomingCallLambda(e){return{[`${e.slug}IncomingCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:pe.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:pe.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:pe.LambdaCode.missedCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createCallLogTable(e){return{[`${e.slug}CallLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCompleteSetup(e){let t={},a={};Object.assign(t,pe.createPhoneLambdaRole({slug:e.slug})),Object.assign(t,pe.createCallLogTable({slug:e.slug})),t[`${e.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-phone-notifications`}},t[`${e.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let r={"Fn::GetAtt":[`${e.slug}PhoneLambdaRole`,"Arn"]},n={Ref:`${e.slug}PhoneNotificationTopic`},i={Ref:`${e.slug}CallLogTable`},s={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(t,pe.createIncomingCallLambda({slug:e.slug,roleArn:r,notificationTopicArn:n,callLogTable:i,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(t,pe.createVoicemailLambda({slug:e.slug,roleArn:r,voicemailBucket:s,notificationTopicArn:n,callLogTable:i,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(t,pe.createMissedCallLambda({slug:e.slug,roleArn:r,notificationTopicArn:n,callLogTable:i,webhookUrl:e.webhookUrl})),a[`${e.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${e.slug}PhoneNotificationTopic`}},a[`${e.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${e.slug}CallLogTable`}},a[`${e.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${e.slug}VoicemailBucket`}},{resources:t,outputs:a}}}class ie{static createQueue(e){let{slug:t,environment:a,name:r,delaySeconds:n=0,visibilityTimeout:i=30,messageRetentionPeriod:s=345600,maxMessageSize:o=262144,receiveMessageWaitTime:c=0,fifo:l=!1,contentBasedDeduplication:u=!1,encrypted:m=!0,kmsKeyId:p}=e,g=r||A({slug:t,environment:a,resourceType:"queue"}),h=l?`${g}.fifo`:g,y=f(g),b={Type:"AWS::SQS::Queue",Properties:{QueueName:h,DelaySeconds:n,MaximumMessageSize:o,MessageRetentionPeriod:s,ReceiveMessageWaitTimeSeconds:c,VisibilityTimeout:i,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:a}]}};if(l)b.Properties.FifoQueue=!0,b.Properties.ContentBasedDeduplication=u;if(m)if(p)b.Properties.KmsMasterKeyId=p;else b.Properties.SqsManagedSseEnabled=!0;return{queue:b,logicalId:y}}static createDeadLetterQueue(e,t){let{slug:a,environment:r,maxReceiveCount:n=3}=t,i=A({slug:a,environment:r,resourceType:"dlq"}),s=f(i),o={Type:"AWS::SQS::Queue",Properties:{QueueName:i,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:r},{Key:"Type",Value:"DeadLetterQueue"}]}},c={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:C.GetAtt(s,"Arn"),maxReceiveCount:n}}};return{deadLetterQueue:o,updatedSourceQueue:c,deadLetterLogicalId:s}}static createSchedule(e,t){let{slug:a,environment:r,name:n,description:i,enabled:s=!0}=t,o=n||A({slug:a,environment:r,resourceType:"schedule"}),c=f(o);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:o,Description:i,ScheduleExpression:e,State:s?"ENABLED":"DISABLED",Targets:[]}},logicalId:c}}static scheduleEcsTask(e,t,a){let{slug:r,environment:n,name:i,description:s,enabled:o=!0,taskDefinitionArn:c,clusterArn:l,subnets:u,securityGroups:m=[],assignPublicIp:p=!1,taskCount:g=1,containerOverrides:h}=a,y=i||A({slug:r,environment:n,resourceType:"ecs-schedule"}),b=f(y),T={Id:"1",Arn:l,RoleArn:t,EcsParameters:{TaskDefinitionArn:c,TaskCount:g,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:u,SecurityGroups:m,AssignPublicIp:p?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(h&&h.length>0)T.Input=JSON.stringify({containerOverrides:h});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:y,Description:s||`Scheduled ECS task: ${c}`,ScheduleExpression:e,State:o?"ENABLED":"DISABLED",Targets:[T]}},logicalId:b}}static scheduleLambda(e,t){let{slug:a,environment:r,name:n,description:i,enabled:s=!0,functionArn:o,input:c}=t,l=n||A({slug:a,environment:r,resourceType:"lambda-schedule"}),u=f(l),m={Id:"1",Arn:o};if(c)m.Input=JSON.stringify(c);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:l,Description:i||`Scheduled Lambda: ${o}`,ScheduleExpression:e,State:s?"ENABLED":"DISABLED",Targets:[m]}},logicalId:u}}static scheduleSqsMessage(e,t){let{slug:a,environment:r,name:n,description:i,enabled:s=!0,queueArn:o,messageGroupId:c}=t,l=n||A({slug:a,environment:r,resourceType:"sqs-schedule"}),u=f(l),m={Id:"1",Arn:o};if(c)m.SqsParameters={MessageGroupId:c};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:l,Description:i||`Scheduled SQS message: ${o}`,ScheduleExpression:e,State:s?"ENABLED":"DISABLED",Targets:[m]}},logicalId:u}}static addTarget(e,t){if(!e.Properties.Targets)e.Properties.Targets=[];let a={Id:t.id,Arn:t.arn};if(t.roleArn)a.RoleArn=t.roleArn;if(t.input)a.Input=JSON.stringify(t.input);return e.Properties.Targets.push(a),e}static toCronExpression(e){if(e.startsWith("cron(")||e.startsWith("rate("))return e;return`cron(${e})`}static rateExpression(e,t){return`rate(${e} ${t})`}static CronExpressions={EveryMinute:"cron(* * * * ? *)",Every5Minutes:"cron(*/5 * * * ? *)",Every15Minutes:"cron(*/15 * * * ? *)",Every30Minutes:"cron(*/30 * * * ? *)",Hourly:"cron(0 * * * ? *)",Daily:"cron(0 0 * * ? *)",DailyAt9AM:"cron(0 9 * * ? *)",DailyAtMidnight:"cron(0 0 * * ? *)",Weekly:"cron(0 0 ? * SUN *)",Monthly:"cron(0 0 1 * ? *)"};static RateExpressions={Every1Minute:"rate(1 minute)",Every5Minutes:"rate(5 minutes)",Every10Minutes:"rate(10 minutes)",Every15Minutes:"rate(15 minutes)",Every30Minutes:"rate(30 minutes)",Every1Hour:"rate(1 hour)",Every6Hours:"rate(6 hours)",Every12Hours:"rate(12 hours)",Every1Day:"rate(1 day)"};static rateStringToExpression(e){let t=e.toLowerCase().trim(),a=t.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(a){let l=parseInt(a[1],10),u=a[2].toLowerCase(),m=u.endsWith("s")&&l===1?u.slice(0,-1):u,p=!u.endsWith("s")&&l>1?`${u}s`:u;return`rate(${l} ${l===1?m:p})`}let r=t.match(/^every\s+(minute|hour|day)$/i);if(r)return`rate(1 ${r[1]})`;let n={"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(n[t])return n[t];let i=t.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(i){let l=parseInt(i[1],10),u=i[2]?.toLowerCase();if(u==="pm"&&l!==12)l+=12;else if(u==="am"&&l===12)l=0;return`cron(0 ${l} * * ? *)`}let s=t.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(s){let l=parseInt(s[1],10);return`cron(${parseInt(s[2],10)} ${l} * * ? *)`}let o={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},c=t.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(c)return`cron(0 0 ? * ${o[c[1].toLowerCase()]} *)`;return ie.toCronExpression(e)}static JobConfig={create:(e)=>{let{name:t,handler:a,retries:r=3,backoff:n="exponential",backoffDelay:i=1000,maxDelay:s=30000,timeout:o=60000,jitter:c=!0}=e;return{name:t,handler:a,retries:r,backoff:n,backoffDelay:i,maxDelay:s,timeout:o,jitter:c}},calculateDelay:(e,t)=>{let{backoff:a,backoffDelay:r,maxDelay:n,jitter:i}=t,s;switch(a){case"linear":s=r*e;break;case"exponential":s=r*2**(e-1);break;case"fixed":default:s=r}if(s=Math.min(s,n||Number.MAX_SAFE_INTEGER),i){let o=s*0.25*Math.random();s+=o}return Math.floor(s)},presets:{fastRetry:{retries:5,backoff:"exponential",backoffDelay:100,maxDelay:5000,jitter:!0},standard:{retries:3,backoff:"exponential",backoffDelay:1000,maxDelay:30000,jitter:!0},longRunning:{retries:2,backoff:"exponential",backoffDelay:5000,maxDelay:60000,timeout:300000,jitter:!0},critical:{retries:10,backoff:"exponential",backoffDelay:500,maxDelay:60000,jitter:!0},noRetry:{retries:0,backoff:"fixed",backoffDelay:0,maxDelay:0,jitter:!1}}};static createJobContainerOverride(e){let{containerName:t,jobClass:a,jobData:r,environment:n={}}=e,i=[{name:"JOB_CLASS",value:a}];if(r)i.push({name:"JOB_DATA",value:JSON.stringify(r)});for(let[s,o]of Object.entries(n))i.push({name:s,value:o});return{name:t,command:["bun","run","app/Jobs/runner.ts"],environment:i}}static createScheduledJob(e){let{slug:t,environment:a,schedule:r,jobClass:n,jobData:i,taskDefinitionArn:s,clusterArn:o,subnets:c,securityGroups:l=[],roleArn:u,containerName:m="app"}=e,p=ie.rateStringToExpression(r),g=ie.createJobContainerOverride({containerName:m,jobClass:n,jobData:i});return ie.scheduleEcsTask(p,u,{slug:t,environment:a,name:`${t}-${n.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${n}`,taskDefinitionArn:s,clusterArn:o,subnets:c,securityGroups:l,containerOverrides:[g]})}static QueuePresets={highThroughput:(e,t)=>ie.createQueue({slug:e,environment:t,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,t)=>ie.createQueue({slug:e,environment:t,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,t)=>ie.createQueue({slug:e,environment:t,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,t,a=60)=>ie.createQueue({slug:e,environment:t,delaySeconds:a})}}class Ce{static async discoverJobs(e){let{projectRoot:t,jobsPath:a="app/Jobs"}=e,r=`${t}/${a}`,n=[];try{let i=await import("node:fs"),s=await import("node:path");if(!i.existsSync(r))return[];let o=i.readdirSync(r).filter((c)=>c.endsWith(".ts")&&!c.startsWith("_")&&c!=="runner.ts");for(let c of o){let l=s.join(r,c),u=c.replace(".ts",""),m=i.readFileSync(l,"utf-8"),p=Ce.parseJobMetadata(m,u,l);if(p)n.push(p)}}catch{return[]}return n}static parseJobMetadata(e,t,a){let r=e.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/schedule:\s*['"`]([^'"`]+)['"`]/),n=e.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||e.match(/enabled:\s*(true|false)/),i=e.match(/export\s+const\s+retries\s*=\s*(\d+)/)||e.match(/retries:\s*(\d+)/),s=e.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||e.match(/timeout:\s*(\d+)/),o=e.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||e.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),c=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;return{name:t,path:a,schedule:r?.[1],handler:`${t}.handle`,enabled:n?.[1]!=="false",retries:i?parseInt(i[1],10):void 0,backoff:o?.[1],timeout:s?parseInt(s[1],10):void 0,description:c?.[1]}}static async discoverActions(e){let{projectRoot:t,actionsPath:a="app/Actions"}=e,r=`${t}/${a}`,n=[];try{let i=await import("node:fs"),s=await import("node:path");if(!i.existsSync(r))return[];let o=i.readdirSync(r).filter((c)=>c.endsWith(".ts")&&!c.startsWith("_"));for(let c of o){let l=s.join(r,c),u=c.replace(".ts",""),m=i.readFileSync(l,"utf-8"),p=Ce.parseActionMetadata(m,u,l);if(p)n.push(p)}}catch{return[]}return n}static parseActionMetadata(e,t,a){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let r=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:t,path:a,handler:`${t}.handle`,description:r?.[1]}}static generateScheduledJobResources(e){let{slug:t,environment:a,jobs:r,taskDefinitionArn:n,clusterArn:i,subnets:s,securityGroups:o=[],roleArn:c,containerName:l="app"}=e,u={},m=0;for(let p of r){if(!p.schedule||!p.enabled)continue;let{rule:g,logicalId:h}=ie.createScheduledJob({slug:t,environment:a,schedule:p.schedule,jobClass:p.name,taskDefinitionArn:n,clusterArn:i,subnets:s,securityGroups:o,roleArn:c,containerName:l});u[h]=g,m++}return{rules:u,count:m}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1661
|
+
`;class ge{static LambdaCode={incomingCall:ja,voicemail:pi,missedCall:mi};static createConnectInstance(e){let{slug:t,environment:a,instanceAlias:r,inboundCallsEnabled:n=!0,outboundCallsEnabled:i=!0}=e;return{[`${t}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:r,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:n,OutboundCalls:i,ContactflowLogs:!0,ContactLens:!0,AutoResolveBestVoices:!0,UseCustomTTSVoices:!1,EarlyMedia:!0}}}}}static createHoursOfOperation(e){return{[`${e.slug}HoursOfOperation`]:{Type:"AWS::Connect::HoursOfOperation",Properties:{InstanceArn:e.instanceArn,Name:e.name,TimeZone:e.timezone,Config:e.schedule.map((t)=>({Day:t.day,StartTime:{Hours:t.startHour,Minutes:t.startMinute},EndTime:{Hours:t.endHour,Minutes:t.endMinute}}))}}}}static createQueue(e){return{[`${e.slug}Queue`]:{Type:"AWS::Connect::Queue",Properties:{InstanceArn:e.instanceArn,Name:e.name,HoursOfOperationArn:e.hoursOfOperationArn,MaxContacts:e.maxContacts||10}}}}static createContactFlow(e){return{[`${e.slug}ContactFlow`]:{Type:"AWS::Connect::ContactFlow",Properties:{InstanceArn:e.instanceArn,Name:e.name,Type:e.type,Content:e.content}}}}static createBasicIvrFlow(e){let t={Version:"2019-10-30",StartAction:"greeting",Actions:[{Identifier:"greeting",Type:"MessageParticipant",Parameters:{Text:e.greeting},Transitions:{NextAction:"transfer_to_queue",Errors:[{NextAction:"disconnect"}]}},{Identifier:"transfer_to_queue",Type:"TransferToQueue",Parameters:{QueueId:e.queueArn},Transitions:{NextAction:e.voicemailLambdaArn?"voicemail":"disconnect",Errors:[{NextAction:"disconnect"}]}},...e.voicemailLambdaArn?[{Identifier:"voicemail",Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:e.voicemailLambdaArn},Transitions:{NextAction:"disconnect",Errors:[{NextAction:"disconnect"}]}}]:[],{Identifier:"disconnect",Type:"DisconnectParticipant",Parameters:{},Transitions:{}}]};return JSON.stringify(t)}static createPhoneLambdaRole(e){return{[`${e.slug}PhoneLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.slug}-phone-lambda-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"PhoneLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"}]}}]}}}}static createIncomingCallLambda(e){return{[`${e.slug}IncomingCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:ge.LambdaCode.incomingCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createVoicemailLambda(e){return{[`${e.slug}VoicemailLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-voicemail`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:300,MemorySize:512,Code:{ZipFile:ge.LambdaCode.voicemail},Environment:{Variables:{VOICEMAIL_BUCKET:e.voicemailBucket,NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",TRANSCRIPTION_ENABLED:e.transcriptionEnabled?"true":"false"}}}}}}static createMissedCallLambda(e){return{[`${e.slug}MissedCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-missed-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:ge.LambdaCode.missedCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",CALL_LOG_TABLE:e.callLogTable||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createCallLogTable(e){return{[`${e.slug}CallLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCompleteSetup(e){let t={},a={};Object.assign(t,ge.createPhoneLambdaRole({slug:e.slug})),Object.assign(t,ge.createCallLogTable({slug:e.slug})),t[`${e.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-phone-notifications`}},t[`${e.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let r={"Fn::GetAtt":[`${e.slug}PhoneLambdaRole`,"Arn"]},n={Ref:`${e.slug}PhoneNotificationTopic`},i={Ref:`${e.slug}CallLogTable`},s={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(t,ge.createIncomingCallLambda({slug:e.slug,roleArn:r,notificationTopicArn:n,callLogTable:i,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(t,ge.createVoicemailLambda({slug:e.slug,roleArn:r,voicemailBucket:s,notificationTopicArn:n,callLogTable:i,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(t,ge.createMissedCallLambda({slug:e.slug,roleArn:r,notificationTopicArn:n,callLogTable:i,webhookUrl:e.webhookUrl})),a[`${e.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${e.slug}PhoneNotificationTopic`}},a[`${e.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${e.slug}CallLogTable`}},a[`${e.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${e.slug}VoicemailBucket`}},{resources:t,outputs:a}}}class se{static createQueue(e){let{slug:t,environment:a,name:r,delaySeconds:n=0,visibilityTimeout:i=30,messageRetentionPeriod:s=345600,maxMessageSize:o=262144,receiveMessageWaitTime:c=0,fifo:l=!1,contentBasedDeduplication:u=!1,encrypted:m=!0,kmsKeyId:p}=e,g=r||A({slug:t,environment:a,resourceType:"queue"}),h=l?`${g}.fifo`:g,y=f(g),b={Type:"AWS::SQS::Queue",Properties:{QueueName:h,DelaySeconds:n,MaximumMessageSize:o,MessageRetentionPeriod:s,ReceiveMessageWaitTimeSeconds:c,VisibilityTimeout:i,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:a}]}};if(l)b.Properties.FifoQueue=!0,b.Properties.ContentBasedDeduplication=u;if(m)if(p)b.Properties.KmsMasterKeyId=p;else b.Properties.SqsManagedSseEnabled=!0;return{queue:b,logicalId:y}}static createDeadLetterQueue(e,t){let{slug:a,environment:r,maxReceiveCount:n=3}=t,i=A({slug:a,environment:r,resourceType:"dlq"}),s=f(i),o={Type:"AWS::SQS::Queue",Properties:{QueueName:i,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:r},{Key:"Type",Value:"DeadLetterQueue"}]}},c={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:C.GetAtt(s,"Arn"),maxReceiveCount:n}}};return{deadLetterQueue:o,updatedSourceQueue:c,deadLetterLogicalId:s}}static createSchedule(e,t){let{slug:a,environment:r,name:n,description:i,enabled:s=!0}=t,o=n||A({slug:a,environment:r,resourceType:"schedule"}),c=f(o);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:o,Description:i,ScheduleExpression:e,State:s?"ENABLED":"DISABLED",Targets:[]}},logicalId:c}}static scheduleEcsTask(e,t,a){let{slug:r,environment:n,name:i,description:s,enabled:o=!0,taskDefinitionArn:c,clusterArn:l,subnets:u,securityGroups:m=[],assignPublicIp:p=!1,taskCount:g=1,containerOverrides:h}=a,y=i||A({slug:r,environment:n,resourceType:"ecs-schedule"}),b=f(y),T={Id:"1",Arn:l,RoleArn:t,EcsParameters:{TaskDefinitionArn:c,TaskCount:g,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:u,SecurityGroups:m,AssignPublicIp:p?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(h&&h.length>0)T.Input=JSON.stringify({containerOverrides:h});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:y,Description:s||`Scheduled ECS task: ${c}`,ScheduleExpression:e,State:o?"ENABLED":"DISABLED",Targets:[T]}},logicalId:b}}static scheduleLambda(e,t){let{slug:a,environment:r,name:n,description:i,enabled:s=!0,functionArn:o,input:c}=t,l=n||A({slug:a,environment:r,resourceType:"lambda-schedule"}),u=f(l),m={Id:"1",Arn:o};if(c)m.Input=JSON.stringify(c);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:l,Description:i||`Scheduled Lambda: ${o}`,ScheduleExpression:e,State:s?"ENABLED":"DISABLED",Targets:[m]}},logicalId:u}}static scheduleSqsMessage(e,t){let{slug:a,environment:r,name:n,description:i,enabled:s=!0,queueArn:o,messageGroupId:c}=t,l=n||A({slug:a,environment:r,resourceType:"sqs-schedule"}),u=f(l),m={Id:"1",Arn:o};if(c)m.SqsParameters={MessageGroupId:c};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:l,Description:i||`Scheduled SQS message: ${o}`,ScheduleExpression:e,State:s?"ENABLED":"DISABLED",Targets:[m]}},logicalId:u}}static addTarget(e,t){if(!e.Properties.Targets)e.Properties.Targets=[];let a={Id:t.id,Arn:t.arn};if(t.roleArn)a.RoleArn=t.roleArn;if(t.input)a.Input=JSON.stringify(t.input);return e.Properties.Targets.push(a),e}static toCronExpression(e){if(e.startsWith("cron(")||e.startsWith("rate("))return e;return`cron(${e})`}static rateExpression(e,t){return`rate(${e} ${t})`}static CronExpressions={EveryMinute:"cron(* * * * ? *)",Every5Minutes:"cron(*/5 * * * ? *)",Every15Minutes:"cron(*/15 * * * ? *)",Every30Minutes:"cron(*/30 * * * ? *)",Hourly:"cron(0 * * * ? *)",Daily:"cron(0 0 * * ? *)",DailyAt9AM:"cron(0 9 * * ? *)",DailyAtMidnight:"cron(0 0 * * ? *)",Weekly:"cron(0 0 ? * SUN *)",Monthly:"cron(0 0 1 * ? *)"};static RateExpressions={Every1Minute:"rate(1 minute)",Every5Minutes:"rate(5 minutes)",Every10Minutes:"rate(10 minutes)",Every15Minutes:"rate(15 minutes)",Every30Minutes:"rate(30 minutes)",Every1Hour:"rate(1 hour)",Every6Hours:"rate(6 hours)",Every12Hours:"rate(12 hours)",Every1Day:"rate(1 day)"};static rateStringToExpression(e){let t=e.toLowerCase().trim(),a=t.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(a){let l=parseInt(a[1],10),u=a[2].toLowerCase(),m=u.endsWith("s")&&l===1?u.slice(0,-1):u,p=!u.endsWith("s")&&l>1?`${u}s`:u;return`rate(${l} ${l===1?m:p})`}let r=t.match(/^every\s+(minute|hour|day)$/i);if(r)return`rate(1 ${r[1]})`;let n={"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(n[t])return n[t];let i=t.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(i){let l=parseInt(i[1],10),u=i[2]?.toLowerCase();if(u==="pm"&&l!==12)l+=12;else if(u==="am"&&l===12)l=0;return`cron(0 ${l} * * ? *)`}let s=t.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(s){let l=parseInt(s[1],10);return`cron(${parseInt(s[2],10)} ${l} * * ? *)`}let o={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},c=t.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(c)return`cron(0 0 ? * ${o[c[1].toLowerCase()]} *)`;return se.toCronExpression(e)}static JobConfig={create:(e)=>{let{name:t,handler:a,retries:r=3,backoff:n="exponential",backoffDelay:i=1000,maxDelay:s=30000,timeout:o=60000,jitter:c=!0}=e;return{name:t,handler:a,retries:r,backoff:n,backoffDelay:i,maxDelay:s,timeout:o,jitter:c}},calculateDelay:(e,t)=>{let{backoff:a,backoffDelay:r,maxDelay:n,jitter:i}=t,s;switch(a){case"linear":s=r*e;break;case"exponential":s=r*2**(e-1);break;case"fixed":default:s=r}if(s=Math.min(s,n||Number.MAX_SAFE_INTEGER),i){let o=s*0.25*Math.random();s+=o}return Math.floor(s)},presets:{fastRetry:{retries:5,backoff:"exponential",backoffDelay:100,maxDelay:5000,jitter:!0},standard:{retries:3,backoff:"exponential",backoffDelay:1000,maxDelay:30000,jitter:!0},longRunning:{retries:2,backoff:"exponential",backoffDelay:5000,maxDelay:60000,timeout:300000,jitter:!0},critical:{retries:10,backoff:"exponential",backoffDelay:500,maxDelay:60000,jitter:!0},noRetry:{retries:0,backoff:"fixed",backoffDelay:0,maxDelay:0,jitter:!1}}};static createJobContainerOverride(e){let{containerName:t,jobClass:a,jobData:r,environment:n={}}=e,i=[{name:"JOB_CLASS",value:a}];if(r)i.push({name:"JOB_DATA",value:JSON.stringify(r)});for(let[s,o]of Object.entries(n))i.push({name:s,value:o});return{name:t,command:["bun","run","app/Jobs/runner.ts"],environment:i}}static createScheduledJob(e){let{slug:t,environment:a,schedule:r,jobClass:n,jobData:i,taskDefinitionArn:s,clusterArn:o,subnets:c,securityGroups:l=[],roleArn:u,containerName:m="app"}=e,p=se.rateStringToExpression(r),g=se.createJobContainerOverride({containerName:m,jobClass:n,jobData:i});return se.scheduleEcsTask(p,u,{slug:t,environment:a,name:`${t}-${n.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${n}`,taskDefinitionArn:s,clusterArn:o,subnets:c,securityGroups:l,containerOverrides:[g]})}static QueuePresets={highThroughput:(e,t)=>se.createQueue({slug:e,environment:t,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,t)=>se.createQueue({slug:e,environment:t,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,t)=>se.createQueue({slug:e,environment:t,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,t,a=60)=>se.createQueue({slug:e,environment:t,delaySeconds:a})}}class Te{static async discoverJobs(e){let{projectRoot:t,jobsPath:a="app/Jobs"}=e,r=`${t}/${a}`,n=[];try{let i=await import("node:fs"),s=await import("node:path");if(!i.existsSync(r))return[];let o=i.readdirSync(r).filter((c)=>c.endsWith(".ts")&&!c.startsWith("_")&&c!=="runner.ts");for(let c of o){let l=s.join(r,c),u=c.replace(".ts",""),m=i.readFileSync(l,"utf-8"),p=Te.parseJobMetadata(m,u,l);if(p)n.push(p)}}catch{return[]}return n}static parseJobMetadata(e,t,a){let r=e.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/schedule:\s*['"`]([^'"`]+)['"`]/),n=e.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||e.match(/enabled:\s*(true|false)/),i=e.match(/export\s+const\s+retries\s*=\s*(\d+)/)||e.match(/retries:\s*(\d+)/),s=e.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||e.match(/timeout:\s*(\d+)/),o=e.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||e.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),c=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;return{name:t,path:a,schedule:r?.[1],handler:`${t}.handle`,enabled:n?.[1]!=="false",retries:i?parseInt(i[1],10):void 0,backoff:o?.[1],timeout:s?parseInt(s[1],10):void 0,description:c?.[1]}}static async discoverActions(e){let{projectRoot:t,actionsPath:a="app/Actions"}=e,r=`${t}/${a}`,n=[];try{let i=await import("node:fs"),s=await import("node:path");if(!i.existsSync(r))return[];let o=i.readdirSync(r).filter((c)=>c.endsWith(".ts")&&!c.startsWith("_"));for(let c of o){let l=s.join(r,c),u=c.replace(".ts",""),m=i.readFileSync(l,"utf-8"),p=Te.parseActionMetadata(m,u,l);if(p)n.push(p)}}catch{return[]}return n}static parseActionMetadata(e,t,a){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let r=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:t,path:a,handler:`${t}.handle`,description:r?.[1]}}static generateScheduledJobResources(e){let{slug:t,environment:a,jobs:r,taskDefinitionArn:n,clusterArn:i,subnets:s,securityGroups:o=[],roleArn:c,containerName:l="app"}=e,u={},m=0;for(let p of r){if(!p.schedule||!p.enabled)continue;let{rule:g,logicalId:h}=se.createScheduledJob({slug:t,environment:a,schedule:p.schedule,jobClass:p.name,taskDefinitionArn:n,clusterArn:i,subnets:s,securityGroups:o,roleArn:c,containerName:l});u[h]=g,m++}return{rules:u,count:m}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1662
1662
|
/**
|
|
1663
1663
|
* Job Runner Script
|
|
1664
1664
|
* This script is invoked by ECS scheduled tasks to run jobs
|
|
@@ -1703,7 +1703,7 @@ catch (error) {
|
|
|
1703
1703
|
}
|
|
1704
1704
|
|
|
1705
1705
|
run()
|
|
1706
|
-
`}static async generateJobManifest(e){let t=await
|
|
1706
|
+
`}static async generateJobManifest(e){let t=await Te.discoverJobs(e),a=t.filter((r)=>r.schedule&&r.enabled);return{jobs:t,scheduledCount:a.length,totalCount:t.length}}}var Cl={loadJobs:Te.discoverJobs,loadActions:Te.discoverActions,generateScheduledJobs:Te.generateScheduledJobResources,generateRunner:Te.generateJobRunnerScript,paths:{jobs:"app/Jobs",actions:"app/Actions",runner:"app/Jobs/runner.ts"}},gi=`
|
|
1707
1707
|
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1708
1708
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1709
1709
|
|
|
@@ -1826,7 +1826,7 @@ catch (error) {
|
|
|
1826
1826
|
|
|
1827
1827
|
return { statusCode: 200, body: 'OK' };
|
|
1828
1828
|
};
|
|
1829
|
-
`,
|
|
1829
|
+
`,hi=`
|
|
1830
1830
|
const { DynamoDBClient, PutItemCommand, DeleteItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1831
1831
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1832
1832
|
|
|
@@ -1978,7 +1978,7 @@ catch (error) {
|
|
|
1978
1978
|
|
|
1979
1979
|
return { statusCode: 200, body: 'OK' };
|
|
1980
1980
|
};
|
|
1981
|
-
`,
|
|
1981
|
+
`,yi={};De(yi,{default:()=>fi,handler:()=>Ka});var Ka=`
|
|
1982
1982
|
const { PinpointClient, SendMessagesCommand } = require('@aws-sdk/client-pinpoint');
|
|
1983
1983
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1984
1984
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
@@ -2142,7 +2142,7 @@ function resolveTemplate(template, data) {
|
|
|
2142
2142
|
}
|
|
2143
2143
|
return result;
|
|
2144
2144
|
}
|
|
2145
|
-
`,
|
|
2145
|
+
`,fi=`
|
|
2146
2146
|
const { PinpointClient, SendMessagesCommand } = require('@aws-sdk/client-pinpoint');
|
|
2147
2147
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
2148
2148
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
@@ -2306,14 +2306,14 @@ function resolveTemplate(template, data) {
|
|
|
2306
2306
|
}
|
|
2307
2307
|
return result;
|
|
2308
2308
|
}
|
|
2309
|
-
`;class z{static LambdaCode={send:Ka,receive:gi,deliveryStatus:pi};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let t={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)t.SenderId=e.senderId;if(e.shortCode)t.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:t}}}static createSmsLambdaRole(e){return{[`${e.slug}SmsLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.slug}-sms-lambda-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"SmsLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetSmsChannel"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem","dynamodb:DeleteItem"],Resource:"*"}]}}]}}}}static createSendLambda(e){return{[`${e.slug}SmsSendLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-send`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:z.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:z.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:z.LambdaCode.deliveryStatus},Environment:{Variables:{MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createMessageLogTable(e){return{[`${e.slug}SmsMessageLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-messages`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createOptOutTable(e){return{[`${e.slug}SmsOptOutTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-optouts`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}}static createNotificationTopic(e){return{[`${e.slug}SmsNotificationTopic`]:{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-sms-notifications`}}}}static createCompleteSetup(e){let t={},a={};Object.assign(t,z.createPinpointApp({slug:e.slug})),Object.assign(t,z.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(t,z.createSmsLambdaRole({slug:e.slug})),Object.assign(t,z.createMessageLogTable({slug:e.slug})),Object.assign(t,z.createOptOutTable({slug:e.slug})),Object.assign(t,z.createNotificationTopic({slug:e.slug}));let r={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},n={Ref:`${e.slug}PinpointApp`},i={Ref:`${e.slug}SmsMessageLogTable`},s={Ref:`${e.slug}SmsOptOutTable`},o={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(t,z.createSendLambda({slug:e.slug,roleArn:r,pinpointAppId:n,messageLogTable:i,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(t,z.createReceiveLambda({slug:e.slug,roleArn:r,optOutTable:s,messageLogTable:i,notificationTopicArn:o,webhookUrl:e.webhookUrl}));return Object.assign(t,z.createDeliveryStatusLambda({slug:e.slug,roleArn:r,messageLogTable:i,notificationTopicArn:o,webhookUrl:e.webhookUrl})),a[`${e.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${e.slug}PinpointApp`}},a[`${e.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${e.slug}SmsSendLambda`,"Arn"]}},a[`${e.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${e.slug}SmsNotificationTopic`}},a[`${e.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${e.slug}SmsMessageLogTable`}},{resources:t,outputs:a}}}function kt(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((t)=>t.charAt(0).toUpperCase()+t.slice(1)).join("")||"User"}function fi(e,t){let a=(e||t).replace(/^\/+|\/+$/g,"");if(!a||a.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${t}`);return a}function Si(e){let t=e.storage;if(t?.type==="efs"){let r="fileSystemId"in t?t.fileSystemId:void 0;if(!r||typeof r==="string"&&!r.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:r,posixProfile:t.posixProfile}}let a=(t?.type==="s3"?t.bucket??e.bucket:e.bucket)?.trim();if(!a)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:a}}function bi(e,t,a){let r=t.posixProfile??a;if(!r)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let n of[r.uid,r.gid,...r.secondaryGids??[]])if(!Number.isInteger(n)||n<0||n>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${n}`);return{Uid:r.uid,Gid:r.gid,...r.secondaryGids?.length?{SecondaryGids:r.secondaryGids}:{}}}function Ai(e,t){return typeof e==="string"?`/${e}/${t}`:{"Fn::Sub":[`/\${FileSystemId}/${t}`,{FileSystemId:e}]}}function Ci(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 Ti{static create(e){let t=Si(e),a=t.type==="efs"?"EFS":"S3",r=e.endpointType??"PUBLIC";if(r==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let n=`${kt(e.slug)}${kt(e.environment)}Sftp`,i=`${n}Server`,s={},o;if(e.logging!==!1){let c=`${n}LoggingRole`;s[c]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TransferLogging",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:log-group:/aws/transfer/*"}]}}]}},o={"Fn::GetAtt":[c,"Arn"]}}s[i]={Type:"AWS::Transfer::Server",Properties:{Domain:a,EndpointType:r,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...r==="VPC"?{EndpointDetails:{VpcId:e.endpointDetails.vpcId,SubnetIds:e.endpointDetails.subnetIds,...e.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:e.endpointDetails.securityGroupIds}:{},...e.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:e.endpointDetails.addressAllocationIds}:{}}}:{},...e.securityPolicyName?{SecurityPolicyName:e.securityPolicyName}:{},...o?{LoggingRole:o}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[c,l]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(c))throw Error(`sftp: invalid username ${c}`);if(!l.sshPublicKeys.length)throw Error(`sftp: user ${c} requires at least one SSH public key`);let u=kt(c),m=fi(l.homeDirectory,c),p=`${n}${u}User`,g=l.roleArn;if(!g){let h=`${n}${u}Role`,y;if(t.type==="efs")y=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Ci(t.fileSystemId)}];else{let b=`arn:aws:s3:::${t.bucket}`;y=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:b,Condition:{StringLike:{"s3:prefix":[m,`${m}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${b}/${m}/*`}]}s[h]={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:y}}]}},g={"Fn::GetAtt":[h,"Arn"]}}s[p]={Type:"AWS::Transfer::User",DependsOn:[i],Properties:{ServerId:{Ref:i},UserName:c,Role:g,HomeDirectoryType:"PATH",HomeDirectory:t.type==="efs"?Ai(t.fileSystemId,m):`/${t.bucket}/${m}`,...t.type==="efs"?{PosixProfile:bi(c,l,t.posixProfile)}:{},SshPublicKeys:l.sshPublicKeys}}}return{resources:s,serverLogicalId:i,domain:a}}}class ut{static createBedrockRole(e,t){let{slug:a,environment:r,name:n,models:i=["*"],allowStreaming:s=!0}=t,o=n||A({slug:a,environment:r,resourceType:"bedrock-role"}),c=f(o),l=["bedrock:InvokeModel"];if(s)l.push("bedrock:InvokeModelWithResponseStream");let u=i.map((m)=>m==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${m}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:o,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:e},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${o}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:l,Resource:u}]}}],Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r}]}},logicalId:c}}static createBedrockPolicy(e){let{slug:t,environment:a,name:r,models:n=["*"],allowInvoke:i=!0,allowStreaming:s=!0,allowAsync:o=!1}=e,c=r||A({slug:t,environment:a,resourceType:"bedrock-policy"}),l=f(c),u=[];if(i)u.push("bedrock:InvokeModel");if(s)u.push("bedrock:InvokeModelWithResponseStream");if(o)u.push("bedrock:InvokeModelAsync");let m=n.map((p)=>p==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${p}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:u,Resource:m}]}}},logicalId:l}}static enableBedrockForLambda(e){return ut.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return ut.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return ut.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,t=["*"],a=!0){let r=["bedrock:InvokeModel"];if(a)r.push("bedrock:InvokeModelWithResponseStream");let n=t.map((i)=>i==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${i}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:r,Resource:n}]}}),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 Gt{static createPostgres(e){return Gt.createRDSInstance("postgres","16.2",e)}static createMysql(e){return Gt.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,t,a){let{slug:r,environment:n,instanceClass:i="db.t3.micro",allocatedStorage:s=20,storageType:o="gp3",masterUsername:c="admin",masterPassword:l,databaseName:u,subnetIds:m,securityGroupIds:p,encrypted:g=!0,kmsKeyId:h,multiAz:y=!1,backupRetentionDays:b=7,publiclyAccessible:T=!1,enableCloudwatchLogs:w=!0,deletionProtection:S=!0}=a,E=A({slug:r,environment:n,resourceType:`${e}-db`}),v=f(E),P,N;if(m&&m.length>0){let D=A({slug:r,environment:n,resourceType:"db-subnet-group"});N=f(D),P={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:D,DBSubnetGroupDescription:`Subnet group for ${E}`,SubnetIds:m,Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:n}]}}}let I={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:E,DBInstanceClass:i,Engine:e,EngineVersion:t,MasterUsername:c,MasterUserPassword:l,AllocatedStorage:s,StorageType:o,StorageEncrypted:g,MultiAZ:y,BackupRetentionPeriod:b,PubliclyAccessible:T,DeletionProtection:S,Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:n}]}};if(u)I.Properties.DBName=u;if(h)I.Properties.KmsKeyId=h;if(N)I.Properties.DBSubnetGroupName=C.Ref(N);if(p&&p.length>0)I.Properties.VPCSecurityGroups=p;if(w)I.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:I,subnetGroup:P,logicalId:v,subnetGroupId:N}}static createReadReplica(e,t){let{slug:a,environment:r,instanceClass:n="db.t3.micro",securityGroupIds:i,publiclyAccessible:s=!1}=t,o=A({slug:a,environment:r,resourceType:"db-replica"}),c=f(o),l={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:o,DBInstanceClass:n,SourceDBInstanceIdentifier:C.Ref(e),PubliclyAccessible:s,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r},{Key:"Type",Value:"ReadReplica"}]}};if(i&&i.length>0)l.Properties.VPCSecurityGroups=i;return{replica:l,logicalId:c}}static createParameterGroup(e,t,a){let{slug:r,environment:n,parameters:i={}}=a,s=A({slug:r,environment:n,resourceType:"db-params"}),o=f(s),c=e==="postgres"?`postgres${t.split(".")[0]}`:`mysql${t.split(".")[0]}.${t.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:s,Description:`Parameter group for ${s}`,Family:c,Parameters:i,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:n}]}},logicalId:o}}static enableBackup(e,t=7){return e.Properties.BackupRetentionPeriod=t,e}static createTable(e){let{slug:t,environment:a,tableName:r,partitionKey:n,sortKey:i,billingMode:s="PAY_PER_REQUEST",readCapacity:o=5,writeCapacity:c=5,streamEnabled:l=!1,streamViewType:u="NEW_AND_OLD_IMAGES",encrypted:m=!0,kmsKeyId:p,pointInTimeRecovery:g=!0,ttlAttribute:h}=e,y=r||A({slug:t,environment:a,resourceType:"table"}),b=f(y),T=[{AttributeName:n.name,AttributeType:n.type}];if(i)T.push({AttributeName:i.name,AttributeType:i.type});let w=[{AttributeName:n.name,KeyType:"HASH"}];if(i)w.push({AttributeName:i.name,KeyType:"RANGE"});let S={Type:"AWS::DynamoDB::Table",Properties:{TableName:y,BillingMode:s,AttributeDefinitions:T,KeySchema:w,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:a}]}};if(s==="PROVISIONED")S.Properties.ProvisionedThroughput={ReadCapacityUnits:o,WriteCapacityUnits:c};if(l)S.Properties.StreamSpecification={StreamViewType:u};if(m)S.Properties.SSESpecification={SSEEnabled:!0,SSEType:p?"KMS":"AES256",KMSMasterKeyId:p};if(g)S.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(h)S.Properties.TimeToLiveSpecification={AttributeName:h,Enabled:!0};return{table:S,logicalId:b}}static addGlobalSecondaryIndex(e,t){let{indexName:a,partitionKey:r,sortKey:n,projectionType:i="ALL",nonKeyAttributes:s,readCapacity:o=5,writeCapacity:c=5}=t;if(!e.Properties.AttributeDefinitions.some((m)=>m.AttributeName===r.name))e.Properties.AttributeDefinitions.push({AttributeName:r.name,AttributeType:r.type});if(n&&!e.Properties.AttributeDefinitions.some((m)=>m.AttributeName===n.name))e.Properties.AttributeDefinitions.push({AttributeName:n.name,AttributeType:n.type});let l=[{AttributeName:r.name,KeyType:"HASH"}];if(n)l.push({AttributeName:n.name,KeyType:"RANGE"});let u={IndexName:a,KeySchema:l,Projection:{ProjectionType:i,NonKeyAttributes:i==="INCLUDE"?s:void 0},ProvisionedThroughput:void 0};if(e.Properties.BillingMode==="PROVISIONED")u.ProvisionedThroughput={ReadCapacityUnits:o,WriteCapacityUnits:c};if(!e.Properties.GlobalSecondaryIndexes)e.Properties.GlobalSecondaryIndexes=[];return e.Properties.GlobalSecondaryIndexes.push(u),e}static enableStreams(e,t="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:t},e}static InstanceClasses={T3_Micro:"db.t3.micro",T3_Small:"db.t3.small",T3_Medium:"db.t3.medium",T3_Large:"db.t3.large",T4g_Micro:"db.t4g.micro",T4g_Small:"db.t4g.small",T4g_Medium:"db.t4g.medium",M5_Large:"db.m5.large",M5_XLarge:"db.m5.xlarge",M5_2XLarge:"db.m5.2xlarge",R5_Large:"db.r5.large",R5_XLarge:"db.r5.xlarge",R5_2XLarge:"db.r5.2xlarge"}}class vi{static createRedis(e){let{slug:t,environment:a,nodeType:r="cache.t3.micro",engineVersion:n="7.1",port:i=6379,subnetIds:s,securityGroupIds:o,numCacheClusters:c=2,automaticFailover:l=!0,multiAz:u=!0,clusterMode:m=!1,numNodeGroups:p=1,replicasPerNodeGroup:g=1,atRestEncryption:h=!0,transitEncryption:y=!0,authToken:b,kmsKeyId:T,snapshotRetentionDays:w=7,snapshotWindow:S,maintenanceWindow:E}=e,v=A({slug:t,environment:a,resourceType:"redis"}),P=f(v),N,I;if(s&&s.length>0){let M=A({slug:t,environment:a,resourceType:"cache-subnet-group"});I=f(M),N={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:M,Description:`Subnet group for ${v}`,SubnetIds:s,Tags:[{Key:"Name",Value:M},{Key:"Environment",Value:a}]}}}let D={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:v,ReplicationGroupDescription:`Redis cluster for ${t} ${a}`,Engine:"redis",EngineVersion:n,CacheNodeType:r,Port:i,AutomaticFailoverEnabled:l,MultiAZEnabled:u,AtRestEncryptionEnabled:h,TransitEncryptionEnabled:y,SnapshotRetentionLimit:w,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:v},{Key:"Environment",Value:a}]}};if(m)D.Properties.NumNodeGroups=p,D.Properties.ReplicasPerNodeGroup=g;else D.Properties.NumCacheClusters=c;if(b)D.Properties.AuthToken=b;if(T)D.Properties.KmsKeyId=T;if(I)D.Properties.CacheSubnetGroupName=C.Ref(I);if(o&&o.length>0)D.Properties.SecurityGroupIds=o;if(S)D.Properties.SnapshotWindow=S;if(E)D.Properties.PreferredMaintenanceWindow=E;return{replicationGroup:D,subnetGroup:N,logicalId:P,subnetGroupId:I}}static createMemcached(e){let{slug:t,environment:a,nodeType:r="cache.t3.micro",engineVersion:n="1.6.22",port:i=11211,numCacheNodes:s=2,subnetIds:o,securityGroupIds:c,azMode:l="cross-az",preferredAzs:u,maintenanceWindow:m}=e,p=A({slug:t,environment:a,resourceType:"memcached"}),g=f(p),h,y;if(o&&o.length>0){let T=A({slug:t,environment:a,resourceType:"cache-subnet-group"});y=f(T),h={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:T,Description:`Subnet group for ${p}`,SubnetIds:o,Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:a}]}}}let b={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:p,CacheNodeType:r,Engine:"memcached",EngineVersion:n,NumCacheNodes:s,Port:i,AZMode:l,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:a}]}};if(y)b.Properties.CacheSubnetGroupName=C.Ref(y);if(c&&c.length>0)b.Properties.VpcSecurityGroupIds=c;if(u&&u.length>0)b.Properties.PreferredAvailabilityZones=u;if(m)b.Properties.PreferredMaintenanceWindow=m;return{cluster:b,subnetGroup:h,logicalId:g,subnetGroupId:y}}static enableClusterMode(e,t=3,a=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=t,e.Properties.ReplicasPerNodeGroup=a,e}static createRedisParameterGroup(e,t){let{slug:a,environment:r,parameters:n={}}=t,i=A({slug:a,environment:r,resourceType:"redis-params"}),s=f(i);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${i}`,Properties:n,Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:r}]}},logicalId:s}}static createMemcachedParameterGroup(e,t){let{slug:a,environment:r,parameters:n={}}=t,i=A({slug:a,environment:r,resourceType:"memcached-params"}),s=f(i);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${i}`,Properties:n,Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:r}]}},logicalId:s}}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 ne{static createUser(e){let{slug:t,environment:a,userName:r,groups:n,managedPolicyArns:i}=e,s=r||A({slug:t,environment:a,resourceType:"user"}),o=f(s),c={Type:"AWS::IAM::User",Properties:{UserName:s,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:a}]}};if(n&&n.length>0)c.Properties.Groups=n;if(i&&i.length>0)c.Properties.ManagedPolicyArns=i;return{user:c,logicalId:o}}static createRole(e){let{slug:t,environment:a,roleName:r,servicePrincipal:n,awsPrincipal:i,managedPolicyArns:s}=e,o=r||A({slug:t,environment:a,resourceType:"role"}),c=f(o),l={};if(n)l.Service=n;if(i)l.AWS=i;let u={Type:"AWS::IAM::Role",Properties:{RoleName:o,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:l,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:a}]}};if(s&&s.length>0)u.Properties.ManagedPolicyArns=s;return{role:u,logicalId:c}}static createGroup(e){let{slug:t,environment:a,groupName:r,managedPolicyArns:n}=e,i=r||A({slug:t,environment:a,resourceType:"group"}),s=f(i),o={Type:"AWS::IAM::Group",Properties:{GroupName:i}};if(n&&n.length>0)o.Properties.ManagedPolicyArns=n;return{group:o,logicalId:s}}static createPolicy(e){let{slug:t,environment:a,policyName:r,description:n,statements:i}=e,s=r||A({slug:t,environment:a,resourceType:"policy"}),o=f(s),c=i.map((l)=>({Sid:l.sid,Effect:l.effect||"Allow",Action:l.actions,Resource:l.resources,Condition:l.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:s,Description:n||`Managed policy for ${s}`,PolicyDocument:{Version:"2012-10-17",Statement:c}}},logicalId:o}}static attachPolicyToRole(e,t){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(t))e.Properties.ManagedPolicyArns.push(t);return e}static attachPolicyToUser(e,t){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(t))e.Properties.ManagedPolicyArns.push(t);return e}static attachPolicyToGroup(e,t){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(t))e.Properties.ManagedPolicyArns.push(t);return e}static addInlinePolicyToRole(e,t,a){if(!e.Properties.Policies)e.Properties.Policies=[];let r=a.map((n)=>({Effect:n.effect||"Allow",Action:n.actions,Resource:n.resources}));return e.Properties.Policies.push({PolicyName:t,PolicyDocument:{Version:"2012-10-17",Statement:r}}),e}static addInlinePolicyToUser(e,t,a){if(!e.Properties.Policies)e.Properties.Policies=[];let r=a.map((n)=>({Effect:n.effect||"Allow",Action:n.actions,Resource:n.resources}));return e.Properties.Policies.push({PolicyName:t,PolicyDocument:{Version:"2012-10-17",Statement:r}}),e}static createAccessKey(e,t){let{slug:a,environment:r,status:n="Active"}=t,i=A({slug:a,environment:r,resourceType:"access-key"}),s=f(i);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:C.Ref(e),Status:n}},logicalId:s}}static createInstanceProfile(e,t){let{slug:a,environment:r,profileName:n}=t,i=n||A({slug:a,environment:r,resourceType:"instance-profile"}),s=f(i);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:i,Roles:[C.Ref(e)]}},logicalId:s}}static ManagedPolicies={AdministratorAccess:"arn:aws:iam::aws:policy/AdministratorAccess",PowerUserAccess:"arn:aws:iam::aws:policy/PowerUserAccess",ReadOnlyAccess:"arn:aws:iam::aws:policy/ReadOnlyAccess",S3FullAccess:"arn:aws:iam::aws:policy/AmazonS3FullAccess",S3ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",DynamoDBFullAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",DynamoDBReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess",RDSFullAccess:"arn:aws:iam::aws:policy/AmazonRDSFullAccess",RDSReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess",LambdaFullAccess:"arn:aws:iam::aws:policy/AWSLambda_FullAccess",LambdaReadOnlyAccess:"arn:aws:iam::aws:policy/AWSLambda_ReadOnlyAccess",LambdaBasicExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",LambdaVPCAccessExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole",EC2FullAccess:"arn:aws:iam::aws:policy/AmazonEC2FullAccess",EC2ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess",EC2ContainerRegistryReadOnly:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",EC2ContainerRegistryPowerUser:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser",ECSTaskExecutionRole:"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",ECSFullAccess:"arn:aws:iam::aws:policy/AmazonECS_FullAccess",CloudWatchFullAccess:"arn:aws:iam::aws:policy/CloudWatchFullAccess",CloudWatchLogsFullAccess:"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess",SESFullAccess:"arn:aws:iam::aws:policy/AmazonSESFullAccess",SNSFullAccess:"arn:aws:iam::aws:policy/AmazonSNSFullAccess",SQSFullAccess:"arn:aws:iam::aws:policy/AmazonSQSFullAccess",SecretsManagerReadWrite:"arn:aws:iam::aws:policy/SecretsManagerReadWrite"};static ServicePrincipals={Lambda:"lambda.amazonaws.com",EC2:"ec2.amazonaws.com",ECS:"ecs.amazonaws.com",ECSTaskExecution:"ecs-tasks.amazonaws.com",APIGateway:"apigateway.amazonaws.com",Events:"events.amazonaws.com",States:"states.amazonaws.com",CodeBuild:"codebuild.amazonaws.com",CodeDeploy:"codedeploy.amazonaws.com",CloudFormation:"cloudformation.amazonaws.com"};static createCiCdUser(e){let{slug:t,environment:a,permissions:r,createAccessKey:n=!0}=e,i={},s=[];if(r.s3Buckets&&r.s3Buckets.length>0)s.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...r.s3Buckets,...r.s3Buckets.map((g)=>`${g}/*`)]});if(r.cloudFrontDistributions&&r.cloudFrontDistributions.length>0)s.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:r.cloudFrontDistributions});if(r.ecrRepositories&&r.ecrRepositories.length>0)s.push({sid:"ECRAccess",actions:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:GetRepositoryPolicy","ecr:DescribeRepositories","ecr:ListImages","ecr:DescribeImages","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:r.ecrRepositories}),s.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(r.ecsServices&&r.ecsServices.length>0)s.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:r.ecsServices}),s.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),s.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(r.cloudFormationStacks&&r.cloudFormationStacks.length>0)s.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:r.cloudFormationStacks});if(r.lambdaFunctions&&r.lambdaFunctions.length>0)s.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:r.lambdaFunctions});if(r.secretsManagerSecrets&&r.secretsManagerSecrets.length>0)s.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:r.secretsManagerSecrets});let{policy:o,logicalId:c}=ne.createPolicy({slug:t,environment:a,policyName:A({slug:t,environment:a,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${t} (${a})`,statements:s});i[c]=o;let{user:l,logicalId:u}=ne.createUser({slug:t,environment:a,userName:A({slug:t,environment:a,resourceType:"cicd-user"}),managedPolicyArns:[C.Ref(c)]});i[u]=l;let m,p;if(n){let g=ne.createAccessKey(u,{slug:t,environment:a});m=g.accessKey,p=g.logicalId,i[p]=m}return{user:l,accessKey:m,policy:o,userLogicalId:u,accessKeyLogicalId:p,policyLogicalId:c,resources:i}}static createCrossAccountRole(e){let{slug:t,environment:a,trustedAccountIds:r,externalId:n,permissions:i,maxSessionDuration:s=3600}=e,o={},{policy:c,logicalId:l}=ne.createPolicy({slug:t,environment:a,policyName:A({slug:t,environment:a,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${t} (${a})`,statements:i});o[l]=c;let u=A({slug:t,environment:a,resourceType:"cross-account-role"}),m=f(u),p={};if(n)p.StringEquals={"sts:ExternalId":n};let g={Type:"AWS::IAM::Role",Properties:{RoleName:u,MaxSessionDuration:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:r.map((h)=>`arn:aws:iam::${h}:root`)},Action:"sts:AssumeRole",...Object.keys(p).length>0?{Condition:p}:{}}]},ManagedPolicyArns:[C.Ref(l)],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:a},{Key:"Purpose",Value:"Cross-Account Access"}]}};return o[m]=g,{role:g,policy:c,roleLogicalId:m,policyLogicalId:l,resources:o}}static createCliUser(e){let{slug:t,environment:a,permissions:r="readonly"}=e,n={},i=[],s=[];switch(r){case"readonly":s=[ne.ManagedPolicies.ReadOnlyAccess];break;case"deploy":i=[{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":s=[ne.ManagedPolicies.AdministratorAccess];break}let o,c;if(i.length>0){let g=ne.createPolicy({slug:t,environment:a,policyName:A({slug:t,environment:a,resourceType:"cli-policy"}),description:`CLI access policy for ${t} (${a})`,statements:i});o=g.policy,c=g.logicalId,n[c]=o,s=[C.Ref(c)]}let{user:l,logicalId:u}=ne.createUser({slug:t,environment:a,userName:A({slug:t,environment:a,resourceType:"cli-user"}),managedPolicyArns:s});n[u]=l;let{accessKey:m,logicalId:p}=ne.createAccessKey(u,{slug:t,environment:a});return n[p]=m,{user:l,accessKey:m,policy:o,userLogicalId:u,accessKeyLogicalId:p,policyLogicalId:c,resources:n}}static CiCdPolicies={s3Deployment:(e)=>[{sid:"S3ListBuckets",actions:["s3:ListBucket","s3:GetBucketLocation"],resources:e},{sid:"S3Objects",actions:["s3:GetObject","s3:PutObject","s3:DeleteObject"],resources:e.map((t)=>`${t}/*`)}],cloudFrontInvalidation:(e)=>[{sid:"CloudFrontInvalidation",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations"],resources:e}],ecsDeployment:()=>[{sid:"ECSServices",actions:["ecs:DescribeServices","ecs:UpdateService","ecs:DescribeTaskDefinition","ecs:RegisterTaskDefinition"],resources:"*"},{sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}}],ecrPush:(e)=>[{sid:"ECRAuth",actions:["ecr:GetAuthorizationToken"],resources:"*"},{sid:"ECRPush",actions:["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:e}],lambdaDeployment:(e)=>[{sid:"LambdaDeploy",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion"],resources:e}],cloudFormationDeployment:(e)=>[{sid:"CloudFormationDeploy",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate"],resources:e}]}}class wi{static createRestApi(e){let{slug:t,environment:a,name:r,description:n,endpointType:i="REGIONAL",binaryMediaTypes:s,compressionSize:o}=e,c=r||A({slug:t,environment:a,resourceType:"rest-api"}),l=f(c),u={Type:"AWS::ApiGateway::RestApi",Properties:{Name:c,Description:n||`REST API for ${t} ${a}`,EndpointConfiguration:{Types:[i]},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:a}]}};if(s&&s.length>0)u.Properties.BinaryMediaTypes=s;if(o!==void 0)u.Properties.MinimumCompressionSize=o;return{restApi:u,logicalId:l}}static createHttpApi(e){let{slug:t,environment:a,name:r,description:n,corsEnabled:i=!0,corsOrigins:s=["*"],corsMethods:o=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:c=["*"],corsMaxAge:l=86400,corsAllowCredentials:u=!1}=e,m=r||A({slug:t,environment:a,resourceType:"http-api"}),p=f(m),g={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:m,Description:n||`HTTP API for ${t} ${a}`,ProtocolType:"HTTP",Tags:{Name:m,Environment:a}}};if(i)g.Properties.CorsConfiguration={AllowOrigins:s,AllowMethods:o,AllowHeaders:c,MaxAge:l,AllowCredentials:u};return{httpApi:g,logicalId:p}}static createWebSocketApi(e){let{slug:t,environment:a,name:r,description:n}=e,i=r||A({slug:t,environment:a,resourceType:"ws-api"}),s=f(i);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:i,Description:n||`WebSocket API for ${t} ${a}`,ProtocolType:"WEBSOCKET",Tags:{Name:i,Environment:a}}},logicalId:s}}static createDeployment(e,t){let{slug:a,environment:r,description:n}=t,i=A({slug:a,environment:r,resourceType:"api-deployment"}),s=f(i);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:C.Ref(e),Description:n||`Deployment for ${i}`}},logicalId:s}}static createStage(e,t,a){let{slug:r,environment:n,stageName:i,description:s,cacheEnabled:o=!1,cacheSize:c="0.5",variables:l,throttling:u}=a,m=A({slug:r,environment:n,resourceType:"api-stage"}),p=f(m),g={Type:"AWS::ApiGateway::Stage",Properties:{StageName:i||n,RestApiId:C.Ref(e),DeploymentId:C.Ref(t),Description:s,CacheClusterEnabled:o,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:n}]}};if(o)g.Properties.CacheClusterSize=c;if(l)g.Properties.Variables=l;if(u)g.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:u.burstLimit,ThrottlingRateLimit:u.rateLimit}];return{stage:g,logicalId:p}}static createAuthorizer(e,t){let{slug:a,environment:r,name:n,type:i,functionArn:s,identitySource:o,userPoolArns:c,ttl:l=300}=t,u=n||A({slug:a,environment:r,resourceType:"api-authorizer"}),m=f(u),p={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:u,Type:i,RestApiId:C.Ref(e),AuthorizerResultTtlInSeconds:l}};if(i==="TOKEN"||i==="REQUEST"){if(!s)throw Error("Lambda authorizer requires functionArn");p.Properties.AuthorizerUri=s,p.Properties.IdentitySource=o||"method.request.header.Authorization"}if(i==="COGNITO_USER_POOLS"){if(!c||c.length===0)throw Error("Cognito authorizer requires userPoolArns");p.Properties.ProviderARNs=c,p.Properties.IdentitySource=o||"method.request.header.Authorization"}return{authorizer:p,logicalId:m}}static setCors(e,t={}){let{origins:a=["*"],methods:r=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:n=["*"],maxAge:i=86400,allowCredentials:s=!1}=t;return e.Properties.CorsConfiguration={AllowOrigins:a,AllowMethods:r,AllowHeaders:n,MaxAge:i,AllowCredentials:s},e}static addThrottling(e,t=5000,a=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:t,ThrottlingRateLimit:a}),e}static enableCaching(e,t="0.5",a=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=t,!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:a}),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 Z{static createTopic(e){let{slug:t,environment:a,topicName:r,displayName:n,encrypted:i=!1,kmsKeyId:s}=e,o=r||A({slug:t,environment:a,resourceType:"topic"}),c=f(o),l={Type:"AWS::SNS::Topic",Properties:{TopicName:o,DisplayName:n||o,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:a}]}};if(i&&s)l.Properties.KmsMasterKeyId=s;return{topic:l,logicalId:c}}static subscribe(e,t){let{slug:a,environment:r,protocol:n,endpoint:i,filterPolicy:s,rawMessageDelivery:o=!1}=t,c=A({slug:a,environment:r,resourceType:"subscription"}),l=i.replace(/[^a-zA-Z0-9]/g,""),u=l.length>12?l.slice(-12):l,m=f(`${c}-${n}-${u}`),p={Type:"AWS::SNS::Subscription",Properties:{TopicArn:C.Ref(e),Protocol:n,Endpoint:i,RawMessageDelivery:o}};if(s)p.Properties.FilterPolicy=s;return{subscription:p,logicalId:m}}static subscribeEmail(e,t,a){return Z.subscribe(e,{...a,protocol:"email",endpoint:t})}static subscribeLambda(e,t,a){return Z.subscribe(e,{...a,protocol:"lambda",endpoint:t,rawMessageDelivery:!0})}static subscribeSqs(e,t,a){return Z.subscribe(e,{...a,protocol:"sqs",endpoint:t})}static subscribeHttp(e,t,a){let r=t.startsWith("https://")?"https":"http";return Z.subscribe(e,{...a,protocol:r,endpoint:t})}static subscribeSms(e,t,a){return Z.subscribe(e,{...a,protocol:"sms",endpoint:t})}static setTopicPolicy(e,t){let{slug:a,environment:r,allowedPrincipals:n,allowedServices:i,actions:s="SNS:Publish"}=t,o=A({slug:a,environment:r,resourceType:"topic-policy"}),c=f(o),l={};if(n)l.AWS=n;if(i)l.Service=i;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[C.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:l,Action:s,Resource:C.Ref(e)}]}}},logicalId:c}}static allowCloudWatchAlarms(e,t){return Z.setTopicPolicy(e,{...t,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,t){return Z.setTopicPolicy(e,{...t,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,t){return Z.setTopicPolicy(e,{...t,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,t){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=t,e}static addInlineSubscription(e,t,a){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:t,Endpoint:a}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,t,a)=>({[e]:[{numeric:[">=",t,"<=",a]}]}),prefix:(e,t)=>({[e]:[{prefix:t}]}),and:(...e)=>{return Object.assign({},...e)},exists:(e,t)=>({[e]:[{exists:t}]})};static UseCases={createAlertTopic:(e)=>{return Z.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"})},createEventFanout:(e)=>{return Z.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"})},createNotificationTopic:(e)=>{return Z.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}}class Ei{static createStateMachine(e){let{slug:t,environment:a,stateMachineName:r,type:n="STANDARD",definition:i,roleArn:s,loggingConfiguration:o,tracingConfiguration:c}=e,l=r||A({slug:t,environment:a,resourceType:"state-machine"}),u=f(l),m,p,g;if(s)g=s;else{let y=A({slug:t,environment:a,resourceType:"state-machine-role"});p=f(y),m={Type:"AWS::IAM::Role",Properties:{RoleName:y,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:y},{Key:"Environment",Value:a}]}},g=C.GetAtt(p,"Arn")}let h={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:l,StateMachineType:n,DefinitionString:JSON.stringify(i),RoleArn:g,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:a}]}};if(o)h.Properties.LoggingConfiguration={Level:o.level,IncludeExecutionData:o.includeExecutionData,Destinations:o.destinations?.map((y)=>({CloudWatchLogsLogGroup:{LogGroupArn:y}}))};if(c)h.Properties.TracingConfiguration={Enabled:c.enabled};return{stateMachine:h,logicalId:u,role:m,roleLogicalId:p}}static createLambdaTask(e,t){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:t?.parameters||{"Input.$":"$"}},ResultPath:t?.resultPath,Retry:t?.retry,Catch:t?.catch,Next:t?.next,End:t?.end}}static createDynamoDBTask(e,t,a,r){return{Type:"Task",Resource:{GetItem:"arn:aws:states:::dynamodb:getItem",PutItem:"arn:aws:states:::dynamodb:putItem",UpdateItem:"arn:aws:states:::dynamodb:updateItem",DeleteItem:"arn:aws:states:::dynamodb:deleteItem"}[e],Parameters:{TableName:t,...a},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSNSPublishTask(e,t,a){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:t},ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createSQSSendMessageTask(e,t,a){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:t},ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createPassState(e){return{Type:"Pass",Result:e?.result,ResultPath:e?.resultPath,Parameters:e?.parameters,Next:e?.next,End:e?.end}}static createWaitState(e){return{Type:"Wait",Seconds:e.seconds,Timestamp:e.timestamp,SecondsPath:e.secondsPath,TimestampPath:e.timestampPath,Next:e.next,End:e.end}}static createChoiceState(e,t){return{Type:"Choice",Choices:e,Default:t}}static createParallelState(e,t){return{Type:"Parallel",Branches:e,ResultPath:t?.resultPath,Retry:t?.retry,Catch:t?.catch,Next:t?.next,End:t?.end}}static createMapState(e,t){return{Type:"Map",ItemsPath:t?.itemsPath||"$.items",Iterator:e,MaxConcurrency:t?.maxConcurrency,ResultPath:t?.resultPath,Retry:t?.retry,Catch:t?.catch,Next:t?.next,End:t?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,t){return{Type:"Fail",Error:e,Cause:t}}static RetryPolicies={standard:()=>({ErrorEquals:["States.ALL"],IntervalSeconds:2,MaxAttempts:3,BackoffRate:2}),aggressive:()=>({ErrorEquals:["States.TaskFailed","States.Timeout"],IntervalSeconds:1,MaxAttempts:5,BackoffRate:1.5}),custom:(e,t,a,r)=>({ErrorEquals:e,IntervalSeconds:t,MaxAttempts:a,BackoffRate:r})};static CatchPolicies={all:(e,t)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:t||"$.error"}),specific:(e,t,a)=>({ErrorEquals:e,Next:t,ResultPath:a||"$.error"})};static Patterns={sequential:(e,t,a)=>{let r={};return a.forEach((n,i)=>{let s=i===a.length-1;r[n.name]={...n.state,Next:s?void 0:a[i+1].name,End:s}}),{Comment:"Sequential workflow",StartAt:a[0].name,States:r}},fanout:(e,t,a)=>{return{Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:a.map((r)=>r.definition),End:!0}}}},map:(e,t,a,r)=>{return{Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:a,MaxConcurrency:r,End:!0}}}},withErrorHandling:(e,t,a,r)=>{return{Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...a,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:r,Success:{Type:"Succeed"}}}}}}class Ha{static createAlarm(e){let{slug:t,environment:a,alarmName:r,metricName:n,namespace:i,statistic:s="Average",period:o=300,evaluationPeriods:c=1,threshold:l,comparisonOperator:u,treatMissingData:m="notBreaching",actionsEnabled:p=!0,alarmActions:g,okActions:h,insufficientDataActions:y,dimensions:b,unit:T,datapointsToAlarm:w}=e,S=r||A({slug:t,environment:a,resourceType:"alarm"}),E=f(S),v={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:S,MetricName:n,Namespace:i,Statistic:s,Period:o,EvaluationPeriods:c,Threshold:l,ComparisonOperator:u,TreatMissingData:m,ActionsEnabled:p}};if(g&&g.length>0)v.Properties.AlarmActions=g;if(h&&h.length>0)v.Properties.OKActions=h;if(y&&y.length>0)v.Properties.InsufficientDataActions=y;if(b)v.Properties.Dimensions=Object.entries(b).map(([P,N])=>({Name:P,Value:N}));if(T)v.Properties.Unit=T;if(w!==void 0)v.Properties.DatapointsToAlarm=w;return{alarm:v,logicalId:E}}static createCompositeAlarm(e){let{slug:t,environment:a,alarmName:r,alarmRule:n,actionsEnabled:i=!0,alarmActions:s,okActions:o,insufficientDataActions:c}=e,l=r||A({slug:t,environment:a,resourceType:"composite-alarm"}),u=f(l),m={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:l,AlarmRule:n,ActionsEnabled:i}};if(s&&s.length>0)m.Properties.AlarmActions=s;if(o&&o.length>0)m.Properties.OKActions=o;if(c&&c.length>0)m.Properties.InsufficientDataActions=c;return{alarm:m,logicalId:u}}static createDashboard(e){let{slug:t,environment:a,dashboardName:r,widgets:n}=e,i=r||A({slug:t,environment:a,resourceType:"dashboard"}),s=f(i),o={widgets:n.map((c)=>({type:c.type,x:c.x,y:c.y,width:c.width,height:c.height,properties:c.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:i,DashboardBody:JSON.stringify(o)}},logicalId:s}}static createLogGroup(e){let{slug:t,environment:a,logGroupName:r,retentionInDays:n,kmsKeyId:i}=e,s=r||A({slug:t,environment:a,resourceType:"log-group"}),o=f(s),c={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:s}};if(n!==void 0)c.Properties.RetentionInDays=n;if(i)c.Properties.KmsKeyId=i;return{logGroup:c,logicalId:o}}static createLogStream(e,t){let{slug:a,environment:r,logStreamName:n}=t,i=n||A({slug:a,environment:r,resourceType:"log-stream"}),s=f(i);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:C.Ref(e),LogStreamName:i}},logicalId:s}}static createMetricFilter(e,t){let{slug:a,environment:r,filterName:n,filterPattern:i,metricTransformations:s}=t,o=n||A({slug:a,environment:r,resourceType:"metric-filter"}),c=f(o);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:C.Ref(e),FilterPattern:i,MetricTransformations:s.map((l)=>({MetricName:l.metricName,MetricNamespace:l.metricNamespace,MetricValue:l.metricValue,DefaultValue:l.defaultValue,Unit:l.unit}))}},logicalId:c}}static AlarmTypes={highCpu:(e,t,a,r=80,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:a},alarmActions:n?[n]:void 0}),highMemory:(e,t,a,r=80,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:a},alarmActions:n?[n]:void 0}),highDisk:(e,t,a,r=80,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:a,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:n?[n]:void 0}),lambdaErrors:(e,t,a,r=5,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:a},alarmActions:n?[n]:void 0}),lambdaThrottles:(e,t,a,r=10,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:a},alarmActions:n?[n]:void 0}),apiGateway5xxErrors:(e,t,a,r=10,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:a},alarmActions:n?[n]:void 0}),apiGateway4xxErrors:(e,t,a,r=50,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:a},alarmActions:n?[n]:void 0}),dynamoDBThrottles:(e,t,a,r=5,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:a},alarmActions:n?[n]:void 0}),rdsCpu:(e,t,a,r=80,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:a},alarmActions:n?[n]:void 0}),rdsFreeStorage:(e,t,a,r=5368709120,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:a},alarmActions:n?[n]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,t,a,r=100,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:a},alarmActions:n?[n]:void 0}),albUnhealthyTargets:(e,t,a,r,n=1,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:a,TargetGroup:r},alarmActions:i?[i]:void 0}),sesBounceRate:(e,t,a=5,r)=>({slug:e,environment:t,alarmName:`${e}-${t}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:a/100,comparisonOperator:"GreaterThanThreshold",alarmActions:r?[r]:void 0}),sesComplaintRate:(e,t,a=0.1,r)=>({slug:e,environment:t,alarmName:`${e}-${t}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:a/100,comparisonOperator:"GreaterThanThreshold",alarmActions:r?[r]:void 0}),smsDeliveryFailure:(e,t,a,r=10,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:a},alarmActions:n?[n]:void 0}),smsSpendLimit:(e,t,a=100,r)=>({slug:e,environment:t,alarmName:`${e}-${t}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:a,comparisonOperator:"GreaterThanThreshold",alarmActions:r?[r]:void 0}),connectMissedCalls:(e,t,a,r=5,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:a},alarmActions:n?[n]:void 0})};static DashboardWidgets={metric:(e,t,a,r,n,i)=>({type:"metric",x:e,y:t,width:a,height:r,properties:{metrics:n,title:i||"Metrics",region:"us-east-1",period:300}}),text:(e,t,a,r,n)=>({type:"text",x:e,y:t,width:a,height:r,properties:{markdown:n}}),log:(e,t,a,r,n,i)=>({type:"log",x:e,y:t,width:a,height:r,properties:{query:`SOURCE '${n.join("' | SOURCE '")}'
|
|
2309
|
+
`;class z{static LambdaCode={send:Ka,receive:hi,deliveryStatus:gi};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let t={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)t.SenderId=e.senderId;if(e.shortCode)t.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:t}}}static createSmsLambdaRole(e){return{[`${e.slug}SmsLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${e.slug}-sms-lambda-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"SmsLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetSmsChannel"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem","dynamodb:DeleteItem"],Resource:"*"}]}}]}}}}static createSendLambda(e){return{[`${e.slug}SmsSendLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-send`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:z.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:z.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:z.LambdaCode.deliveryStatus},Environment:{Variables:{MESSAGE_LOG_TABLE:e.messageLogTable||"",NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||"",WEBHOOK_URL:e.webhookUrl||""}}}}}}static createMessageLogTable(e){return{[`${e.slug}SmsMessageLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-messages`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createOptOutTable(e){return{[`${e.slug}SmsOptOutTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-optouts`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}}static createNotificationTopic(e){return{[`${e.slug}SmsNotificationTopic`]:{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-sms-notifications`}}}}static createCompleteSetup(e){let t={},a={};Object.assign(t,z.createPinpointApp({slug:e.slug})),Object.assign(t,z.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(t,z.createSmsLambdaRole({slug:e.slug})),Object.assign(t,z.createMessageLogTable({slug:e.slug})),Object.assign(t,z.createOptOutTable({slug:e.slug})),Object.assign(t,z.createNotificationTopic({slug:e.slug}));let r={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},n={Ref:`${e.slug}PinpointApp`},i={Ref:`${e.slug}SmsMessageLogTable`},s={Ref:`${e.slug}SmsOptOutTable`},o={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(t,z.createSendLambda({slug:e.slug,roleArn:r,pinpointAppId:n,messageLogTable:i,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(t,z.createReceiveLambda({slug:e.slug,roleArn:r,optOutTable:s,messageLogTable:i,notificationTopicArn:o,webhookUrl:e.webhookUrl}));return Object.assign(t,z.createDeliveryStatusLambda({slug:e.slug,roleArn:r,messageLogTable:i,notificationTopicArn:o,webhookUrl:e.webhookUrl})),a[`${e.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${e.slug}PinpointApp`}},a[`${e.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${e.slug}SmsSendLambda`,"Arn"]}},a[`${e.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${e.slug}SmsNotificationTopic`}},a[`${e.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${e.slug}SmsMessageLogTable`}},{resources:t,outputs:a}}}function $t(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((t)=>t.charAt(0).toUpperCase()+t.slice(1)).join("")||"User"}function Si(e,t){let a=(e||t).replace(/^\/+|\/+$/g,"");if(!a||a.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${t}`);return a}function bi(e){let t=e.storage;if(t?.type==="efs"){let r="fileSystemId"in t?t.fileSystemId:void 0;if(!r||typeof r==="string"&&!r.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:r,posixProfile:t.posixProfile}}let a=(t?.type==="s3"?t.bucket??e.bucket:e.bucket)?.trim();if(!a)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:a}}function Ai(e,t,a){let r=t.posixProfile??a;if(!r)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let n of[r.uid,r.gid,...r.secondaryGids??[]])if(!Number.isInteger(n)||n<0||n>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${n}`);return{Uid:r.uid,Gid:r.gid,...r.secondaryGids?.length?{SecondaryGids:r.secondaryGids}:{}}}function Ci(e,t){return typeof e==="string"?`/${e}/${t}`:{"Fn::Sub":[`/\${FileSystemId}/${t}`,{FileSystemId:e}]}}function Ti(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 vi{static create(e){let t=bi(e),a=t.type==="efs"?"EFS":"S3",r=e.endpointType??"PUBLIC";if(r==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let n=`${$t(e.slug)}${$t(e.environment)}Sftp`,i=`${n}Server`,s={},o;if(e.logging!==!1){let c=`${n}LoggingRole`;s[c]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TransferLogging",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:log-group:/aws/transfer/*"}]}}]}},o={"Fn::GetAtt":[c,"Arn"]}}s[i]={Type:"AWS::Transfer::Server",Properties:{Domain:a,EndpointType:r,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...r==="VPC"?{EndpointDetails:{VpcId:e.endpointDetails.vpcId,SubnetIds:e.endpointDetails.subnetIds,...e.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:e.endpointDetails.securityGroupIds}:{},...e.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:e.endpointDetails.addressAllocationIds}:{}}}:{},...e.securityPolicyName?{SecurityPolicyName:e.securityPolicyName}:{},...o?{LoggingRole:o}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[c,l]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(c))throw Error(`sftp: invalid username ${c}`);if(!l.sshPublicKeys.length)throw Error(`sftp: user ${c} requires at least one SSH public key`);let u=$t(c),m=Si(l.homeDirectory,c),p=`${n}${u}User`,g=l.roleArn;if(!g){let h=`${n}${u}Role`,y;if(t.type==="efs")y=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Ti(t.fileSystemId)}];else{let b=`arn:aws:s3:::${t.bucket}`;y=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:b,Condition:{StringLike:{"s3:prefix":[m,`${m}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${b}/${m}/*`}]}s[h]={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:y}}]}},g={"Fn::GetAtt":[h,"Arn"]}}s[p]={Type:"AWS::Transfer::User",DependsOn:[i],Properties:{ServerId:{Ref:i},UserName:c,Role:g,HomeDirectoryType:"PATH",HomeDirectory:t.type==="efs"?Ci(t.fileSystemId,m):`/${t.bucket}/${m}`,...t.type==="efs"?{PosixProfile:Ai(c,l,t.posixProfile)}:{},SshPublicKeys:l.sshPublicKeys}}}return{resources:s,serverLogicalId:i,domain:a}}}class dt{static createBedrockRole(e,t){let{slug:a,environment:r,name:n,models:i=["*"],allowStreaming:s=!0}=t,o=n||A({slug:a,environment:r,resourceType:"bedrock-role"}),c=f(o),l=["bedrock:InvokeModel"];if(s)l.push("bedrock:InvokeModelWithResponseStream");let u=i.map((m)=>m==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${m}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:o,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:e},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${o}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:l,Resource:u}]}}],Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r}]}},logicalId:c}}static createBedrockPolicy(e){let{slug:t,environment:a,name:r,models:n=["*"],allowInvoke:i=!0,allowStreaming:s=!0,allowAsync:o=!1}=e,c=r||A({slug:t,environment:a,resourceType:"bedrock-policy"}),l=f(c),u=[];if(i)u.push("bedrock:InvokeModel");if(s)u.push("bedrock:InvokeModelWithResponseStream");if(o)u.push("bedrock:InvokeModelAsync");let m=n.map((p)=>p==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${p}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:u,Resource:m}]}}},logicalId:l}}static enableBedrockForLambda(e){return dt.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return dt.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return dt.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,t=["*"],a=!0){let r=["bedrock:InvokeModel"];if(a)r.push("bedrock:InvokeModelWithResponseStream");let n=t.map((i)=>i==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${i}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:r,Resource:n}]}}),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 Ft{static createPostgres(e){return Ft.createRDSInstance("postgres","16.2",e)}static createMysql(e){return Ft.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,t,a){let{slug:r,environment:n,instanceClass:i="db.t3.micro",allocatedStorage:s=20,storageType:o="gp3",masterUsername:c="admin",masterPassword:l,databaseName:u,subnetIds:m,securityGroupIds:p,encrypted:g=!0,kmsKeyId:h,multiAz:y=!1,backupRetentionDays:b=7,publiclyAccessible:T=!1,enableCloudwatchLogs:w=!0,deletionProtection:S=!0}=a,E=A({slug:r,environment:n,resourceType:`${e}-db`}),v=f(E),P,N;if(m&&m.length>0){let D=A({slug:r,environment:n,resourceType:"db-subnet-group"});N=f(D),P={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:D,DBSubnetGroupDescription:`Subnet group for ${E}`,SubnetIds:m,Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:n}]}}}let I={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:E,DBInstanceClass:i,Engine:e,EngineVersion:t,MasterUsername:c,MasterUserPassword:l,AllocatedStorage:s,StorageType:o,StorageEncrypted:g,MultiAZ:y,BackupRetentionPeriod:b,PubliclyAccessible:T,DeletionProtection:S,Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:n}]}};if(u)I.Properties.DBName=u;if(h)I.Properties.KmsKeyId=h;if(N)I.Properties.DBSubnetGroupName=C.Ref(N);if(p&&p.length>0)I.Properties.VPCSecurityGroups=p;if(w)I.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:I,subnetGroup:P,logicalId:v,subnetGroupId:N}}static createReadReplica(e,t){let{slug:a,environment:r,instanceClass:n="db.t3.micro",securityGroupIds:i,publiclyAccessible:s=!1}=t,o=A({slug:a,environment:r,resourceType:"db-replica"}),c=f(o),l={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:o,DBInstanceClass:n,SourceDBInstanceIdentifier:C.Ref(e),PubliclyAccessible:s,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:r},{Key:"Type",Value:"ReadReplica"}]}};if(i&&i.length>0)l.Properties.VPCSecurityGroups=i;return{replica:l,logicalId:c}}static createParameterGroup(e,t,a){let{slug:r,environment:n,parameters:i={}}=a,s=A({slug:r,environment:n,resourceType:"db-params"}),o=f(s),c=e==="postgres"?`postgres${t.split(".")[0]}`:`mysql${t.split(".")[0]}.${t.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:s,Description:`Parameter group for ${s}`,Family:c,Parameters:i,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:n}]}},logicalId:o}}static enableBackup(e,t=7){return e.Properties.BackupRetentionPeriod=t,e}static createTable(e){let{slug:t,environment:a,tableName:r,partitionKey:n,sortKey:i,billingMode:s="PAY_PER_REQUEST",readCapacity:o=5,writeCapacity:c=5,streamEnabled:l=!1,streamViewType:u="NEW_AND_OLD_IMAGES",encrypted:m=!0,kmsKeyId:p,pointInTimeRecovery:g=!0,ttlAttribute:h}=e,y=r||A({slug:t,environment:a,resourceType:"table"}),b=f(y),T=[{AttributeName:n.name,AttributeType:n.type}];if(i)T.push({AttributeName:i.name,AttributeType:i.type});let w=[{AttributeName:n.name,KeyType:"HASH"}];if(i)w.push({AttributeName:i.name,KeyType:"RANGE"});let S={Type:"AWS::DynamoDB::Table",Properties:{TableName:y,BillingMode:s,AttributeDefinitions:T,KeySchema:w,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:a}]}};if(s==="PROVISIONED")S.Properties.ProvisionedThroughput={ReadCapacityUnits:o,WriteCapacityUnits:c};if(l)S.Properties.StreamSpecification={StreamViewType:u};if(m)S.Properties.SSESpecification={SSEEnabled:!0,SSEType:p?"KMS":"AES256",KMSMasterKeyId:p};if(g)S.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(h)S.Properties.TimeToLiveSpecification={AttributeName:h,Enabled:!0};return{table:S,logicalId:b}}static addGlobalSecondaryIndex(e,t){let{indexName:a,partitionKey:r,sortKey:n,projectionType:i="ALL",nonKeyAttributes:s,readCapacity:o=5,writeCapacity:c=5}=t;if(!e.Properties.AttributeDefinitions.some((m)=>m.AttributeName===r.name))e.Properties.AttributeDefinitions.push({AttributeName:r.name,AttributeType:r.type});if(n&&!e.Properties.AttributeDefinitions.some((m)=>m.AttributeName===n.name))e.Properties.AttributeDefinitions.push({AttributeName:n.name,AttributeType:n.type});let l=[{AttributeName:r.name,KeyType:"HASH"}];if(n)l.push({AttributeName:n.name,KeyType:"RANGE"});let u={IndexName:a,KeySchema:l,Projection:{ProjectionType:i,NonKeyAttributes:i==="INCLUDE"?s:void 0},ProvisionedThroughput:void 0};if(e.Properties.BillingMode==="PROVISIONED")u.ProvisionedThroughput={ReadCapacityUnits:o,WriteCapacityUnits:c};if(!e.Properties.GlobalSecondaryIndexes)e.Properties.GlobalSecondaryIndexes=[];return e.Properties.GlobalSecondaryIndexes.push(u),e}static enableStreams(e,t="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:t},e}static InstanceClasses={T3_Micro:"db.t3.micro",T3_Small:"db.t3.small",T3_Medium:"db.t3.medium",T3_Large:"db.t3.large",T4g_Micro:"db.t4g.micro",T4g_Small:"db.t4g.small",T4g_Medium:"db.t4g.medium",M5_Large:"db.m5.large",M5_XLarge:"db.m5.xlarge",M5_2XLarge:"db.m5.2xlarge",R5_Large:"db.r5.large",R5_XLarge:"db.r5.xlarge",R5_2XLarge:"db.r5.2xlarge"}}class wi{static createRedis(e){let{slug:t,environment:a,nodeType:r="cache.t3.micro",engineVersion:n="7.1",port:i=6379,subnetIds:s,securityGroupIds:o,numCacheClusters:c=2,automaticFailover:l=!0,multiAz:u=!0,clusterMode:m=!1,numNodeGroups:p=1,replicasPerNodeGroup:g=1,atRestEncryption:h=!0,transitEncryption:y=!0,authToken:b,kmsKeyId:T,snapshotRetentionDays:w=7,snapshotWindow:S,maintenanceWindow:E}=e,v=A({slug:t,environment:a,resourceType:"redis"}),P=f(v),N,I;if(s&&s.length>0){let L=A({slug:t,environment:a,resourceType:"cache-subnet-group"});I=f(L),N={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:L,Description:`Subnet group for ${v}`,SubnetIds:s,Tags:[{Key:"Name",Value:L},{Key:"Environment",Value:a}]}}}let D={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:v,ReplicationGroupDescription:`Redis cluster for ${t} ${a}`,Engine:"redis",EngineVersion:n,CacheNodeType:r,Port:i,AutomaticFailoverEnabled:l,MultiAZEnabled:u,AtRestEncryptionEnabled:h,TransitEncryptionEnabled:y,SnapshotRetentionLimit:w,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:v},{Key:"Environment",Value:a}]}};if(m)D.Properties.NumNodeGroups=p,D.Properties.ReplicasPerNodeGroup=g;else D.Properties.NumCacheClusters=c;if(b)D.Properties.AuthToken=b;if(T)D.Properties.KmsKeyId=T;if(I)D.Properties.CacheSubnetGroupName=C.Ref(I);if(o&&o.length>0)D.Properties.SecurityGroupIds=o;if(S)D.Properties.SnapshotWindow=S;if(E)D.Properties.PreferredMaintenanceWindow=E;return{replicationGroup:D,subnetGroup:N,logicalId:P,subnetGroupId:I}}static createMemcached(e){let{slug:t,environment:a,nodeType:r="cache.t3.micro",engineVersion:n="1.6.22",port:i=11211,numCacheNodes:s=2,subnetIds:o,securityGroupIds:c,azMode:l="cross-az",preferredAzs:u,maintenanceWindow:m}=e,p=A({slug:t,environment:a,resourceType:"memcached"}),g=f(p),h,y;if(o&&o.length>0){let T=A({slug:t,environment:a,resourceType:"cache-subnet-group"});y=f(T),h={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:T,Description:`Subnet group for ${p}`,SubnetIds:o,Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:a}]}}}let b={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:p,CacheNodeType:r,Engine:"memcached",EngineVersion:n,NumCacheNodes:s,Port:i,AZMode:l,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:a}]}};if(y)b.Properties.CacheSubnetGroupName=C.Ref(y);if(c&&c.length>0)b.Properties.VpcSecurityGroupIds=c;if(u&&u.length>0)b.Properties.PreferredAvailabilityZones=u;if(m)b.Properties.PreferredMaintenanceWindow=m;return{cluster:b,subnetGroup:h,logicalId:g,subnetGroupId:y}}static enableClusterMode(e,t=3,a=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=t,e.Properties.ReplicasPerNodeGroup=a,e}static createRedisParameterGroup(e,t){let{slug:a,environment:r,parameters:n={}}=t,i=A({slug:a,environment:r,resourceType:"redis-params"}),s=f(i);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${i}`,Properties:n,Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:r}]}},logicalId:s}}static createMemcachedParameterGroup(e,t){let{slug:a,environment:r,parameters:n={}}=t,i=A({slug:a,environment:r,resourceType:"memcached-params"}),s=f(i);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${i}`,Properties:n,Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:r}]}},logicalId:s}}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 ie{static createUser(e){let{slug:t,environment:a,userName:r,groups:n,managedPolicyArns:i}=e,s=r||A({slug:t,environment:a,resourceType:"user"}),o=f(s),c={Type:"AWS::IAM::User",Properties:{UserName:s,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:a}]}};if(n&&n.length>0)c.Properties.Groups=n;if(i&&i.length>0)c.Properties.ManagedPolicyArns=i;return{user:c,logicalId:o}}static createRole(e){let{slug:t,environment:a,roleName:r,servicePrincipal:n,awsPrincipal:i,managedPolicyArns:s}=e,o=r||A({slug:t,environment:a,resourceType:"role"}),c=f(o),l={};if(n)l.Service=n;if(i)l.AWS=i;let u={Type:"AWS::IAM::Role",Properties:{RoleName:o,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:l,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:a}]}};if(s&&s.length>0)u.Properties.ManagedPolicyArns=s;return{role:u,logicalId:c}}static createGroup(e){let{slug:t,environment:a,groupName:r,managedPolicyArns:n}=e,i=r||A({slug:t,environment:a,resourceType:"group"}),s=f(i),o={Type:"AWS::IAM::Group",Properties:{GroupName:i}};if(n&&n.length>0)o.Properties.ManagedPolicyArns=n;return{group:o,logicalId:s}}static createPolicy(e){let{slug:t,environment:a,policyName:r,description:n,statements:i}=e,s=r||A({slug:t,environment:a,resourceType:"policy"}),o=f(s),c=i.map((l)=>({Sid:l.sid,Effect:l.effect||"Allow",Action:l.actions,Resource:l.resources,Condition:l.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:s,Description:n||`Managed policy for ${s}`,PolicyDocument:{Version:"2012-10-17",Statement:c}}},logicalId:o}}static attachPolicyToRole(e,t){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(t))e.Properties.ManagedPolicyArns.push(t);return e}static attachPolicyToUser(e,t){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(t))e.Properties.ManagedPolicyArns.push(t);return e}static attachPolicyToGroup(e,t){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(t))e.Properties.ManagedPolicyArns.push(t);return e}static addInlinePolicyToRole(e,t,a){if(!e.Properties.Policies)e.Properties.Policies=[];let r=a.map((n)=>({Effect:n.effect||"Allow",Action:n.actions,Resource:n.resources}));return e.Properties.Policies.push({PolicyName:t,PolicyDocument:{Version:"2012-10-17",Statement:r}}),e}static addInlinePolicyToUser(e,t,a){if(!e.Properties.Policies)e.Properties.Policies=[];let r=a.map((n)=>({Effect:n.effect||"Allow",Action:n.actions,Resource:n.resources}));return e.Properties.Policies.push({PolicyName:t,PolicyDocument:{Version:"2012-10-17",Statement:r}}),e}static createAccessKey(e,t){let{slug:a,environment:r,status:n="Active"}=t,i=A({slug:a,environment:r,resourceType:"access-key"}),s=f(i);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:C.Ref(e),Status:n}},logicalId:s}}static createInstanceProfile(e,t){let{slug:a,environment:r,profileName:n}=t,i=n||A({slug:a,environment:r,resourceType:"instance-profile"}),s=f(i);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:i,Roles:[C.Ref(e)]}},logicalId:s}}static ManagedPolicies={AdministratorAccess:"arn:aws:iam::aws:policy/AdministratorAccess",PowerUserAccess:"arn:aws:iam::aws:policy/PowerUserAccess",ReadOnlyAccess:"arn:aws:iam::aws:policy/ReadOnlyAccess",S3FullAccess:"arn:aws:iam::aws:policy/AmazonS3FullAccess",S3ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",DynamoDBFullAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",DynamoDBReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess",RDSFullAccess:"arn:aws:iam::aws:policy/AmazonRDSFullAccess",RDSReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess",LambdaFullAccess:"arn:aws:iam::aws:policy/AWSLambda_FullAccess",LambdaReadOnlyAccess:"arn:aws:iam::aws:policy/AWSLambda_ReadOnlyAccess",LambdaBasicExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",LambdaVPCAccessExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole",EC2FullAccess:"arn:aws:iam::aws:policy/AmazonEC2FullAccess",EC2ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess",EC2ContainerRegistryReadOnly:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",EC2ContainerRegistryPowerUser:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser",ECSTaskExecutionRole:"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",ECSFullAccess:"arn:aws:iam::aws:policy/AmazonECS_FullAccess",CloudWatchFullAccess:"arn:aws:iam::aws:policy/CloudWatchFullAccess",CloudWatchLogsFullAccess:"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess",SESFullAccess:"arn:aws:iam::aws:policy/AmazonSESFullAccess",SNSFullAccess:"arn:aws:iam::aws:policy/AmazonSNSFullAccess",SQSFullAccess:"arn:aws:iam::aws:policy/AmazonSQSFullAccess",SecretsManagerReadWrite:"arn:aws:iam::aws:policy/SecretsManagerReadWrite"};static ServicePrincipals={Lambda:"lambda.amazonaws.com",EC2:"ec2.amazonaws.com",ECS:"ecs.amazonaws.com",ECSTaskExecution:"ecs-tasks.amazonaws.com",APIGateway:"apigateway.amazonaws.com",Events:"events.amazonaws.com",States:"states.amazonaws.com",CodeBuild:"codebuild.amazonaws.com",CodeDeploy:"codedeploy.amazonaws.com",CloudFormation:"cloudformation.amazonaws.com"};static createCiCdUser(e){let{slug:t,environment:a,permissions:r,createAccessKey:n=!0}=e,i={},s=[];if(r.s3Buckets&&r.s3Buckets.length>0)s.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...r.s3Buckets,...r.s3Buckets.map((g)=>`${g}/*`)]});if(r.cloudFrontDistributions&&r.cloudFrontDistributions.length>0)s.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:r.cloudFrontDistributions});if(r.ecrRepositories&&r.ecrRepositories.length>0)s.push({sid:"ECRAccess",actions:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:GetRepositoryPolicy","ecr:DescribeRepositories","ecr:ListImages","ecr:DescribeImages","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:r.ecrRepositories}),s.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(r.ecsServices&&r.ecsServices.length>0)s.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:r.ecsServices}),s.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),s.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(r.cloudFormationStacks&&r.cloudFormationStacks.length>0)s.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:r.cloudFormationStacks});if(r.lambdaFunctions&&r.lambdaFunctions.length>0)s.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:r.lambdaFunctions});if(r.secretsManagerSecrets&&r.secretsManagerSecrets.length>0)s.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:r.secretsManagerSecrets});let{policy:o,logicalId:c}=ie.createPolicy({slug:t,environment:a,policyName:A({slug:t,environment:a,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${t} (${a})`,statements:s});i[c]=o;let{user:l,logicalId:u}=ie.createUser({slug:t,environment:a,userName:A({slug:t,environment:a,resourceType:"cicd-user"}),managedPolicyArns:[C.Ref(c)]});i[u]=l;let m,p;if(n){let g=ie.createAccessKey(u,{slug:t,environment:a});m=g.accessKey,p=g.logicalId,i[p]=m}return{user:l,accessKey:m,policy:o,userLogicalId:u,accessKeyLogicalId:p,policyLogicalId:c,resources:i}}static createCrossAccountRole(e){let{slug:t,environment:a,trustedAccountIds:r,externalId:n,permissions:i,maxSessionDuration:s=3600}=e,o={},{policy:c,logicalId:l}=ie.createPolicy({slug:t,environment:a,policyName:A({slug:t,environment:a,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${t} (${a})`,statements:i});o[l]=c;let u=A({slug:t,environment:a,resourceType:"cross-account-role"}),m=f(u),p={};if(n)p.StringEquals={"sts:ExternalId":n};let g={Type:"AWS::IAM::Role",Properties:{RoleName:u,MaxSessionDuration:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:r.map((h)=>`arn:aws:iam::${h}:root`)},Action:"sts:AssumeRole",...Object.keys(p).length>0?{Condition:p}:{}}]},ManagedPolicyArns:[C.Ref(l)],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:a},{Key:"Purpose",Value:"Cross-Account Access"}]}};return o[m]=g,{role:g,policy:c,roleLogicalId:m,policyLogicalId:l,resources:o}}static createCliUser(e){let{slug:t,environment:a,permissions:r="readonly"}=e,n={},i=[],s=[];switch(r){case"readonly":s=[ie.ManagedPolicies.ReadOnlyAccess];break;case"deploy":i=[{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":s=[ie.ManagedPolicies.AdministratorAccess];break}let o,c;if(i.length>0){let g=ie.createPolicy({slug:t,environment:a,policyName:A({slug:t,environment:a,resourceType:"cli-policy"}),description:`CLI access policy for ${t} (${a})`,statements:i});o=g.policy,c=g.logicalId,n[c]=o,s=[C.Ref(c)]}let{user:l,logicalId:u}=ie.createUser({slug:t,environment:a,userName:A({slug:t,environment:a,resourceType:"cli-user"}),managedPolicyArns:s});n[u]=l;let{accessKey:m,logicalId:p}=ie.createAccessKey(u,{slug:t,environment:a});return n[p]=m,{user:l,accessKey:m,policy:o,userLogicalId:u,accessKeyLogicalId:p,policyLogicalId:c,resources:n}}static CiCdPolicies={s3Deployment:(e)=>[{sid:"S3ListBuckets",actions:["s3:ListBucket","s3:GetBucketLocation"],resources:e},{sid:"S3Objects",actions:["s3:GetObject","s3:PutObject","s3:DeleteObject"],resources:e.map((t)=>`${t}/*`)}],cloudFrontInvalidation:(e)=>[{sid:"CloudFrontInvalidation",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations"],resources:e}],ecsDeployment:()=>[{sid:"ECSServices",actions:["ecs:DescribeServices","ecs:UpdateService","ecs:DescribeTaskDefinition","ecs:RegisterTaskDefinition"],resources:"*"},{sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}}],ecrPush:(e)=>[{sid:"ECRAuth",actions:["ecr:GetAuthorizationToken"],resources:"*"},{sid:"ECRPush",actions:["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:e}],lambdaDeployment:(e)=>[{sid:"LambdaDeploy",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion"],resources:e}],cloudFormationDeployment:(e)=>[{sid:"CloudFormationDeploy",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate"],resources:e}]}}class Ei{static createRestApi(e){let{slug:t,environment:a,name:r,description:n,endpointType:i="REGIONAL",binaryMediaTypes:s,compressionSize:o}=e,c=r||A({slug:t,environment:a,resourceType:"rest-api"}),l=f(c),u={Type:"AWS::ApiGateway::RestApi",Properties:{Name:c,Description:n||`REST API for ${t} ${a}`,EndpointConfiguration:{Types:[i]},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:a}]}};if(s&&s.length>0)u.Properties.BinaryMediaTypes=s;if(o!==void 0)u.Properties.MinimumCompressionSize=o;return{restApi:u,logicalId:l}}static createHttpApi(e){let{slug:t,environment:a,name:r,description:n,corsEnabled:i=!0,corsOrigins:s=["*"],corsMethods:o=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:c=["*"],corsMaxAge:l=86400,corsAllowCredentials:u=!1}=e,m=r||A({slug:t,environment:a,resourceType:"http-api"}),p=f(m),g={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:m,Description:n||`HTTP API for ${t} ${a}`,ProtocolType:"HTTP",Tags:{Name:m,Environment:a}}};if(i)g.Properties.CorsConfiguration={AllowOrigins:s,AllowMethods:o,AllowHeaders:c,MaxAge:l,AllowCredentials:u};return{httpApi:g,logicalId:p}}static createWebSocketApi(e){let{slug:t,environment:a,name:r,description:n}=e,i=r||A({slug:t,environment:a,resourceType:"ws-api"}),s=f(i);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:i,Description:n||`WebSocket API for ${t} ${a}`,ProtocolType:"WEBSOCKET",Tags:{Name:i,Environment:a}}},logicalId:s}}static createDeployment(e,t){let{slug:a,environment:r,description:n}=t,i=A({slug:a,environment:r,resourceType:"api-deployment"}),s=f(i);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:C.Ref(e),Description:n||`Deployment for ${i}`}},logicalId:s}}static createStage(e,t,a){let{slug:r,environment:n,stageName:i,description:s,cacheEnabled:o=!1,cacheSize:c="0.5",variables:l,throttling:u}=a,m=A({slug:r,environment:n,resourceType:"api-stage"}),p=f(m),g={Type:"AWS::ApiGateway::Stage",Properties:{StageName:i||n,RestApiId:C.Ref(e),DeploymentId:C.Ref(t),Description:s,CacheClusterEnabled:o,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:n}]}};if(o)g.Properties.CacheClusterSize=c;if(l)g.Properties.Variables=l;if(u)g.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:u.burstLimit,ThrottlingRateLimit:u.rateLimit}];return{stage:g,logicalId:p}}static createAuthorizer(e,t){let{slug:a,environment:r,name:n,type:i,functionArn:s,identitySource:o,userPoolArns:c,ttl:l=300}=t,u=n||A({slug:a,environment:r,resourceType:"api-authorizer"}),m=f(u),p={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:u,Type:i,RestApiId:C.Ref(e),AuthorizerResultTtlInSeconds:l}};if(i==="TOKEN"||i==="REQUEST"){if(!s)throw Error("Lambda authorizer requires functionArn");p.Properties.AuthorizerUri=s,p.Properties.IdentitySource=o||"method.request.header.Authorization"}if(i==="COGNITO_USER_POOLS"){if(!c||c.length===0)throw Error("Cognito authorizer requires userPoolArns");p.Properties.ProviderARNs=c,p.Properties.IdentitySource=o||"method.request.header.Authorization"}return{authorizer:p,logicalId:m}}static setCors(e,t={}){let{origins:a=["*"],methods:r=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:n=["*"],maxAge:i=86400,allowCredentials:s=!1}=t;return e.Properties.CorsConfiguration={AllowOrigins:a,AllowMethods:r,AllowHeaders:n,MaxAge:i,AllowCredentials:s},e}static addThrottling(e,t=5000,a=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:t,ThrottlingRateLimit:a}),e}static enableCaching(e,t="0.5",a=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=t,!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:a}),e}static CacheSizes={Small:"0.5",Medium:"1.6",Large:"6.1",XLarge:"13.5",XXLarge:"28.4",XXXLarge:"58.2",Huge:"118",Massive:"237"};static ThrottlingPresets={Light:{burstLimit:100,rateLimit:50},Medium:{burstLimit:500,rateLimit:250},Heavy:{burstLimit:2000,rateLimit:1000},Default:{burstLimit:5000,rateLimit:1e4}}}class ee{static createTopic(e){let{slug:t,environment:a,topicName:r,displayName:n,encrypted:i=!1,kmsKeyId:s}=e,o=r||A({slug:t,environment:a,resourceType:"topic"}),c=f(o),l={Type:"AWS::SNS::Topic",Properties:{TopicName:o,DisplayName:n||o,Tags:[{Key:"Name",Value:o},{Key:"Environment",Value:a}]}};if(i&&s)l.Properties.KmsMasterKeyId=s;return{topic:l,logicalId:c}}static subscribe(e,t){let{slug:a,environment:r,protocol:n,endpoint:i,filterPolicy:s,rawMessageDelivery:o=!1}=t,c=A({slug:a,environment:r,resourceType:"subscription"}),l=i.replace(/[^a-zA-Z0-9]/g,""),u=l.length>12?l.slice(-12):l,m=f(`${c}-${n}-${u}`),p={Type:"AWS::SNS::Subscription",Properties:{TopicArn:C.Ref(e),Protocol:n,Endpoint:i,RawMessageDelivery:o}};if(s)p.Properties.FilterPolicy=s;return{subscription:p,logicalId:m}}static subscribeEmail(e,t,a){return ee.subscribe(e,{...a,protocol:"email",endpoint:t})}static subscribeLambda(e,t,a){return ee.subscribe(e,{...a,protocol:"lambda",endpoint:t,rawMessageDelivery:!0})}static subscribeSqs(e,t,a){return ee.subscribe(e,{...a,protocol:"sqs",endpoint:t})}static subscribeHttp(e,t,a){let r=t.startsWith("https://")?"https":"http";return ee.subscribe(e,{...a,protocol:r,endpoint:t})}static subscribeSms(e,t,a){return ee.subscribe(e,{...a,protocol:"sms",endpoint:t})}static setTopicPolicy(e,t){let{slug:a,environment:r,allowedPrincipals:n,allowedServices:i,actions:s="SNS:Publish"}=t,o=A({slug:a,environment:r,resourceType:"topic-policy"}),c=f(o),l={};if(n)l.AWS=n;if(i)l.Service=i;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[C.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:l,Action:s,Resource:C.Ref(e)}]}}},logicalId:c}}static allowCloudWatchAlarms(e,t){return ee.setTopicPolicy(e,{...t,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,t){return ee.setTopicPolicy(e,{...t,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,t){return ee.setTopicPolicy(e,{...t,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,t){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=t,e}static addInlineSubscription(e,t,a){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:t,Endpoint:a}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,t,a)=>({[e]:[{numeric:[">=",t,"<=",a]}]}),prefix:(e,t)=>({[e]:[{prefix:t}]}),and:(...e)=>Object.assign({},...e),exists:(e,t)=>({[e]:[{exists:t}]})};static UseCases={createAlertTopic:(e)=>ee.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>ee.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>ee.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class Pi{static createStateMachine(e){let{slug:t,environment:a,stateMachineName:r,type:n="STANDARD",definition:i,roleArn:s,loggingConfiguration:o,tracingConfiguration:c}=e,l=r||A({slug:t,environment:a,resourceType:"state-machine"}),u=f(l),m,p,g;if(s)g=s;else{let y=A({slug:t,environment:a,resourceType:"state-machine-role"});p=f(y),m={Type:"AWS::IAM::Role",Properties:{RoleName:y,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:y},{Key:"Environment",Value:a}]}},g=C.GetAtt(p,"Arn")}let h={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:l,StateMachineType:n,DefinitionString:JSON.stringify(i),RoleArn:g,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:a}]}};if(o)h.Properties.LoggingConfiguration={Level:o.level,IncludeExecutionData:o.includeExecutionData,Destinations:o.destinations?.map((y)=>({CloudWatchLogsLogGroup:{LogGroupArn:y}}))};if(c)h.Properties.TracingConfiguration={Enabled:c.enabled};return{stateMachine:h,logicalId:u,role:m,roleLogicalId:p}}static createLambdaTask(e,t){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:t?.parameters||{"Input.$":"$"}},ResultPath:t?.resultPath,Retry:t?.retry,Catch:t?.catch,Next:t?.next,End:t?.end}}static createDynamoDBTask(e,t,a,r){return{Type:"Task",Resource:{GetItem:"arn:aws:states:::dynamodb:getItem",PutItem:"arn:aws:states:::dynamodb:putItem",UpdateItem:"arn:aws:states:::dynamodb:updateItem",DeleteItem:"arn:aws:states:::dynamodb:deleteItem"}[e],Parameters:{TableName:t,...a},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSNSPublishTask(e,t,a){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:t},ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createSQSSendMessageTask(e,t,a){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:t},ResultPath:a?.resultPath,Retry:a?.retry,Catch:a?.catch,Next:a?.next,End:a?.end}}static createPassState(e){return{Type:"Pass",Result:e?.result,ResultPath:e?.resultPath,Parameters:e?.parameters,Next:e?.next,End:e?.end}}static createWaitState(e){return{Type:"Wait",Seconds:e.seconds,Timestamp:e.timestamp,SecondsPath:e.secondsPath,TimestampPath:e.timestampPath,Next:e.next,End:e.end}}static createChoiceState(e,t){return{Type:"Choice",Choices:e,Default:t}}static createParallelState(e,t){return{Type:"Parallel",Branches:e,ResultPath:t?.resultPath,Retry:t?.retry,Catch:t?.catch,Next:t?.next,End:t?.end}}static createMapState(e,t){return{Type:"Map",ItemsPath:t?.itemsPath||"$.items",Iterator:e,MaxConcurrency:t?.maxConcurrency,ResultPath:t?.resultPath,Retry:t?.retry,Catch:t?.catch,Next:t?.next,End:t?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,t){return{Type:"Fail",Error:e,Cause:t}}static RetryPolicies={standard:()=>({ErrorEquals:["States.ALL"],IntervalSeconds:2,MaxAttempts:3,BackoffRate:2}),aggressive:()=>({ErrorEquals:["States.TaskFailed","States.Timeout"],IntervalSeconds:1,MaxAttempts:5,BackoffRate:1.5}),custom:(e,t,a,r)=>({ErrorEquals:e,IntervalSeconds:t,MaxAttempts:a,BackoffRate:r})};static CatchPolicies={all:(e,t)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:t||"$.error"}),specific:(e,t,a)=>({ErrorEquals:e,Next:t,ResultPath:a||"$.error"})};static Patterns={sequential:(e,t,a)=>{let r={};return a.forEach((n,i)=>{let s=i===a.length-1;r[n.name]={...n.state,Next:s?void 0:a[i+1].name,End:s}}),{Comment:"Sequential workflow",StartAt:a[0].name,States:r}},fanout:(e,t,a)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:a.map((r)=>r.definition),End:!0}}}),map:(e,t,a,r)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:a,MaxConcurrency:r,End:!0}}}),withErrorHandling:(e,t,a,r)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...a,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:r,Success:{Type:"Succeed"}}})}}class Ha{static createAlarm(e){let{slug:t,environment:a,alarmName:r,metricName:n,namespace:i,statistic:s="Average",period:o=300,evaluationPeriods:c=1,threshold:l,comparisonOperator:u,treatMissingData:m="notBreaching",actionsEnabled:p=!0,alarmActions:g,okActions:h,insufficientDataActions:y,dimensions:b,unit:T,datapointsToAlarm:w}=e,S=r||A({slug:t,environment:a,resourceType:"alarm"}),E=f(S),v={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:S,MetricName:n,Namespace:i,Statistic:s,Period:o,EvaluationPeriods:c,Threshold:l,ComparisonOperator:u,TreatMissingData:m,ActionsEnabled:p}};if(g&&g.length>0)v.Properties.AlarmActions=g;if(h&&h.length>0)v.Properties.OKActions=h;if(y&&y.length>0)v.Properties.InsufficientDataActions=y;if(b)v.Properties.Dimensions=Object.entries(b).map(([P,N])=>({Name:P,Value:N}));if(T)v.Properties.Unit=T;if(w!==void 0)v.Properties.DatapointsToAlarm=w;return{alarm:v,logicalId:E}}static createCompositeAlarm(e){let{slug:t,environment:a,alarmName:r,alarmRule:n,actionsEnabled:i=!0,alarmActions:s,okActions:o,insufficientDataActions:c}=e,l=r||A({slug:t,environment:a,resourceType:"composite-alarm"}),u=f(l),m={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:l,AlarmRule:n,ActionsEnabled:i}};if(s&&s.length>0)m.Properties.AlarmActions=s;if(o&&o.length>0)m.Properties.OKActions=o;if(c&&c.length>0)m.Properties.InsufficientDataActions=c;return{alarm:m,logicalId:u}}static createDashboard(e){let{slug:t,environment:a,dashboardName:r,widgets:n}=e,i=r||A({slug:t,environment:a,resourceType:"dashboard"}),s=f(i),o={widgets:n.map((c)=>({type:c.type,x:c.x,y:c.y,width:c.width,height:c.height,properties:c.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:i,DashboardBody:JSON.stringify(o)}},logicalId:s}}static createLogGroup(e){let{slug:t,environment:a,logGroupName:r,retentionInDays:n,kmsKeyId:i}=e,s=r||A({slug:t,environment:a,resourceType:"log-group"}),o=f(s),c={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:s}};if(n!==void 0)c.Properties.RetentionInDays=n;if(i)c.Properties.KmsKeyId=i;return{logGroup:c,logicalId:o}}static createLogStream(e,t){let{slug:a,environment:r,logStreamName:n}=t,i=n||A({slug:a,environment:r,resourceType:"log-stream"}),s=f(i);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:C.Ref(e),LogStreamName:i}},logicalId:s}}static createMetricFilter(e,t){let{slug:a,environment:r,filterName:n,filterPattern:i,metricTransformations:s}=t,o=n||A({slug:a,environment:r,resourceType:"metric-filter"}),c=f(o);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:C.Ref(e),FilterPattern:i,MetricTransformations:s.map((l)=>({MetricName:l.metricName,MetricNamespace:l.metricNamespace,MetricValue:l.metricValue,DefaultValue:l.defaultValue,Unit:l.unit}))}},logicalId:c}}static AlarmTypes={highCpu:(e,t,a,r=80,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:a},alarmActions:n?[n]:void 0}),highMemory:(e,t,a,r=80,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:a},alarmActions:n?[n]:void 0}),highDisk:(e,t,a,r=80,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:a,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:n?[n]:void 0}),lambdaErrors:(e,t,a,r=5,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:a},alarmActions:n?[n]:void 0}),lambdaThrottles:(e,t,a,r=10,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:a},alarmActions:n?[n]:void 0}),apiGateway5xxErrors:(e,t,a,r=10,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:a},alarmActions:n?[n]:void 0}),apiGateway4xxErrors:(e,t,a,r=50,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:a},alarmActions:n?[n]:void 0}),dynamoDBThrottles:(e,t,a,r=5,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:a},alarmActions:n?[n]:void 0}),rdsCpu:(e,t,a,r=80,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:a},alarmActions:n?[n]:void 0}),rdsFreeStorage:(e,t,a,r=5368709120,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:a},alarmActions:n?[n]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,t,a,r=100,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:a},alarmActions:n?[n]:void 0}),albUnhealthyTargets:(e,t,a,r,n=1,i)=>({slug:e,environment:t,alarmName:`${e}-${t}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:n,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:a,TargetGroup:r},alarmActions:i?[i]:void 0}),sesBounceRate:(e,t,a=5,r)=>({slug:e,environment:t,alarmName:`${e}-${t}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:a/100,comparisonOperator:"GreaterThanThreshold",alarmActions:r?[r]:void 0}),sesComplaintRate:(e,t,a=0.1,r)=>({slug:e,environment:t,alarmName:`${e}-${t}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:a/100,comparisonOperator:"GreaterThanThreshold",alarmActions:r?[r]:void 0}),smsDeliveryFailure:(e,t,a,r=10,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:a},alarmActions:n?[n]:void 0}),smsSpendLimit:(e,t,a=100,r)=>({slug:e,environment:t,alarmName:`${e}-${t}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:a,comparisonOperator:"GreaterThanThreshold",alarmActions:r?[r]:void 0}),connectMissedCalls:(e,t,a,r=5,n)=>({slug:e,environment:t,alarmName:`${e}-${t}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:a},alarmActions:n?[n]:void 0})};static DashboardWidgets={metric:(e,t,a,r,n,i)=>({type:"metric",x:e,y:t,width:a,height:r,properties:{metrics:n,title:i||"Metrics",region:"us-east-1",period:300}}),text:(e,t,a,r,n)=>({type:"text",x:e,y:t,width:a,height:r,properties:{markdown:n}}),log:(e,t,a,r,n,i)=>({type:"log",x:e,y:t,width:a,height:r,properties:{query:`SOURCE '${n.join("' | SOURCE '")}'
|
|
2310
2310
|
| fields @timestamp, @message
|
|
2311
2311
|
| sort @timestamp desc
|
|
2312
2312
|
| limit 20`,region:"us-east-1",title:i||"Logs"}})};static RetentionPeriods={ONE_DAY:1,THREE_DAYS:3,FIVE_DAYS:5,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,TWO_MONTHS:60,THREE_MONTHS:90,FOUR_MONTHS:120,FIVE_MONTHS:150,SIX_MONTHS:180,ONE_YEAR:365,THIRTEEN_MONTHS:400,EIGHTEEN_MONTHS:545,TWO_YEARS:731,FIVE_YEARS:1827,TEN_YEARS:3653,NEVER_EXPIRE:void 0};static FilterPatterns={errors:"[time, request_id, event_type = ERROR*, ...]",all:"",jsonField:(e,t)=>`{ $.${e} = "${t}" }`,httpStatus:(e)=>`[..., status_code = ${e}, ...]`,http4xx:"[..., status_code = 4*, ...]",http5xx:"[..., status_code = 5*, ...]"};static createApplicationDashboard(e){let{slug:t,environment:a,region:r="us-east-1",components:n={}}=e,i=[],s=0;if(i.push({type:"text",x:0,y:s,width:24,height:1,properties:{markdown:`# ${t.toUpperCase()} Dashboard (${a})`}}),s+=1,n.ec2InstanceIds&&n.ec2InstanceIds.length>0)i.push({type:"text",x:0,y:s,width:24,height:1,properties:{markdown:"## EC2 Instances"}}),s+=1,i.push({type:"metric",x:0,y:s,width:8,height:6,properties:{title:"CPU Utilization",region:r,metrics:n.ec2InstanceIds.map((o)=>["AWS/EC2","CPUUtilization","InstanceId",o]),period:300,stat:"Average"}}),i.push({type:"metric",x:8,y:s,width:8,height:6,properties:{title:"Network Traffic",region:r,metrics:[...n.ec2InstanceIds.flatMap((o)=>[["AWS/EC2","NetworkIn","InstanceId",o,{label:`${o} In`}],["AWS/EC2","NetworkOut","InstanceId",o,{label:`${o} Out`}]])],period:300,stat:"Sum"}}),i.push({type:"metric",x:16,y:s,width:8,height:6,properties:{title:"Status Checks",region:r,metrics:n.ec2InstanceIds.map((o)=>["AWS/EC2","StatusCheckFailed","InstanceId",o]),period:60,stat:"Maximum"}}),s+=6;if(n.lambdaFunctionNames&&n.lambdaFunctionNames.length>0)i.push({type:"text",x:0,y:s,width:24,height:1,properties:{markdown:"## Lambda Functions"}}),s+=1,i.push({type:"metric",x:0,y:s,width:8,height:6,properties:{title:"Invocations",region:r,metrics:n.lambdaFunctionNames.map((o)=>["AWS/Lambda","Invocations","FunctionName",o]),period:300,stat:"Sum"}}),i.push({type:"metric",x:8,y:s,width:8,height:6,properties:{title:"Duration",region:r,metrics:n.lambdaFunctionNames.map((o)=>["AWS/Lambda","Duration","FunctionName",o]),period:300,stat:"Average"}}),i.push({type:"metric",x:16,y:s,width:8,height:6,properties:{title:"Errors",region:r,metrics:n.lambdaFunctionNames.map((o)=>["AWS/Lambda","Errors","FunctionName",o]),period:300,stat:"Sum"}}),s+=6;if(n.ecsClusterName&&n.ecsServiceName)i.push({type:"text",x:0,y:s,width:24,height:1,properties:{markdown:"## ECS Service"}}),s+=1,i.push({type:"metric",x:0,y:s,width:8,height:6,properties:{title:"CPU Utilization",region:r,metrics:[["AWS/ECS","CPUUtilization","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:300,stat:"Average"}}),i.push({type:"metric",x:8,y:s,width:8,height:6,properties:{title:"Memory Utilization",region:r,metrics:[["AWS/ECS","MemoryUtilization","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:300,stat:"Average"}}),i.push({type:"metric",x:16,y:s,width:8,height:6,properties:{title:"Running Tasks",region:r,metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}}),s+=6;if(n.albName)i.push({type:"text",x:0,y:s,width:24,height:1,properties:{markdown:"## Application Load Balancer"}}),s+=1,i.push({type:"metric",x:0,y:s,width:8,height:6,properties:{title:"Request Count",region:r,metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",n.albName]],period:60,stat:"Sum"}}),i.push({type:"metric",x:8,y:s,width:8,height:6,properties:{title:"Response Time",region:r,metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",n.albName]],period:60,stat:"Average"}}),i.push({type:"metric",x:16,y:s,width:8,height:6,properties:{title:"HTTP Errors",region:r,metrics:[["AWS/ApplicationELB","HTTPCode_Target_4XX_Count","LoadBalancer",n.albName,{label:"4XX"}],["AWS/ApplicationELB","HTTPCode_Target_5XX_Count","LoadBalancer",n.albName,{label:"5XX"}]],period:60,stat:"Sum"}}),s+=6;if(n.rdsInstanceId)i.push({type:"text",x:0,y:s,width:24,height:1,properties:{markdown:"## RDS Database"}}),s+=1,i.push({type:"metric",x:0,y:s,width:8,height:6,properties:{title:"CPU Utilization",region:r,metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",n.rdsInstanceId]],period:300,stat:"Average"}}),i.push({type:"metric",x:8,y:s,width:8,height:6,properties:{title:"Database Connections",region:r,metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",n.rdsInstanceId]],period:60,stat:"Sum"}}),i.push({type:"metric",x:16,y:s,width:8,height:6,properties:{title:"Free Storage Space",region:r,metrics:[["AWS/RDS","FreeStorageSpace","DBInstanceIdentifier",n.rdsInstanceId]],period:300,stat:"Average"}}),s+=6;if(n.sqsQueueNames&&n.sqsQueueNames.length>0)i.push({type:"text",x:0,y:s,width:24,height:1,properties:{markdown:"## SQS Queues"}}),s+=1,i.push({type:"metric",x:0,y:s,width:12,height:6,properties:{title:"Messages Visible",region:r,metrics:n.sqsQueueNames.map((o)=>["AWS/SQS","ApproximateNumberOfMessagesVisible","QueueName",o]),period:60,stat:"Sum"}}),i.push({type:"metric",x:12,y:s,width:12,height:6,properties:{title:"Message Age",region:r,metrics:n.sqsQueueNames.map((o)=>["AWS/SQS","ApproximateAgeOfOldestMessage","QueueName",o]),period:60,stat:"Maximum"}}),s+=6;if(n.logGroupNames&&n.logGroupNames.length>0)i.push({type:"text",x:0,y:s,width:24,height:1,properties:{markdown:"## Application Logs"}}),s+=1,i.push({type:"log",x:0,y:s,width:24,height:6,properties:{query:`SOURCE '${n.logGroupNames.join("' | SOURCE '")}'
|
|
2313
2313
|
| fields @timestamp, @message
|
|
2314
2314
|
| filter @message like /ERROR|WARN|Exception/
|
|
2315
2315
|
| sort @timestamp desc
|
|
2316
|
-
| limit 50`,region:r,title:"Recent Errors and Warnings"}}),s+=6;return Ha.createDashboard({slug:t,environment:a,widgets:i})}static DashboardTemplates={staticWebsite:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Static Website Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"CloudFront Requests",region:"us-east-1",metrics:[["AWS/CloudFront","Requests","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"Error Rate",region:"us-east-1",metrics:[["AWS/CloudFront","4xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"5XX"}]],period:300,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Bytes Downloaded",region:"us-east-1",metrics:[["AWS/CloudFront","BytesDownloaded","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:e.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",e.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:e.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",e.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",e.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",e.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",e.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",e.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...e.lambdaFunctionNames.map((t,a)=>({type:"metric",x:a%3*8,y:7+Math.floor(a/3)*6,width:8,height:6,properties:{title:`${t} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",t],["AWS/Lambda","Duration","FunctionName",t],["AWS/Lambda","Errors","FunctionName",t]],period:300,stat:"Sum"}}))]}),containerService:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Container Service Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"ECS CPU",region:e.region||"us-east-1",metrics:[["AWS/ECS","CPUUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"ECS Memory",region:e.region||"us-east-1",metrics:[["AWS/ECS","MemoryUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Running Tasks",region:e.region||"us-east-1",metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:0,y:7,width:8,height:6,properties:{title:"ALB Requests",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",e.albName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:7,width:8,height:6,properties:{title:"Response Time",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",e.albName]],period:60,stat:"Average"}},{type:"metric",x:16,y:7,width:8,height:6,properties:{title:"Healthy Hosts",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","HealthyHostCount","LoadBalancer",e.albName]],period:60,stat:"Average"}},...e.rdsInstanceId?[{type:"metric",x:0,y:13,width:12,height:6,properties:{title:"RDS CPU",region:e.region||"us-east-1",metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",e.rdsInstanceId]],period:300,stat:"Average"}},{type:"metric",x:12,y:13,width:12,height:6,properties:{title:"RDS Connections",region:e.region||"us-east-1",metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",e.rdsInstanceId]],period:60,stat:"Sum"}}]:[]]})};static Config={createAlarmConfig:(e)=>{let{metricName:t,namespace:a,threshold:r,comparisonOperator:n="GreaterThanThreshold",evaluationPeriods:i=1,period:s=300,statistic:o="Average",treatMissingData:c="missing"}=e;return{MetricName:t,Namespace:a,Threshold:r,ComparisonOperator:n,EvaluationPeriods:i,Period:s,Statistic:o,TreatMissingData:c}},namespaces:{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",sqs:"AWS/SQS",sns:"AWS/SNS",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apiGateway:"AWS/ApiGateway",dynamodb:"AWS/DynamoDB",elasticache:"AWS/ElastiCache"},comparisonOperators:{greaterThan:"GreaterThanThreshold",greaterOrEqual:"GreaterThanOrEqualToThreshold",lessThan:"LessThanThreshold",lessOrEqual:"LessThanOrEqualToThreshold"},metrics:{ec2:{cpu:{metricName:"CPUUtilization",namespace:"AWS/EC2"},networkIn:{metricName:"NetworkIn",namespace:"AWS/EC2"},networkOut:{metricName:"NetworkOut",namespace:"AWS/EC2"},statusCheck:{metricName:"StatusCheckFailed",namespace:"AWS/EC2"}},ecs:{cpu:{metricName:"CPUUtilization",namespace:"AWS/ECS"},memory:{metricName:"MemoryUtilization",namespace:"AWS/ECS"}},lambda:{invocations:{metricName:"Invocations",namespace:"AWS/Lambda"},errors:{metricName:"Errors",namespace:"AWS/Lambda"},duration:{metricName:"Duration",namespace:"AWS/Lambda"},throttles:{metricName:"Throttles",namespace:"AWS/Lambda"},concurrentExecutions:{metricName:"ConcurrentExecutions",namespace:"AWS/Lambda"}},rds:{cpu:{metricName:"CPUUtilization",namespace:"AWS/RDS"},connections:{metricName:"DatabaseConnections",namespace:"AWS/RDS"},freeStorage:{metricName:"FreeStorageSpace",namespace:"AWS/RDS"},readLatency:{metricName:"ReadLatency",namespace:"AWS/RDS"},writeLatency:{metricName:"WriteLatency",namespace:"AWS/RDS"}},alb:{requestCount:{metricName:"RequestCount",namespace:"AWS/ApplicationELB"},responseTime:{metricName:"TargetResponseTime",namespace:"AWS/ApplicationELB"},httpCode4xx:{metricName:"HTTPCode_Target_4XX_Count",namespace:"AWS/ApplicationELB"},httpCode5xx:{metricName:"HTTPCode_Target_5XX_Count",namespace:"AWS/ApplicationELB"},healthyHosts:{metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB"}},sqs:{messagesVisible:{metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS"},messagesDelayed:{metricName:"ApproximateNumberOfMessagesDelayed",namespace:"AWS/SQS"},messageAge:{metricName:"ApproximateAgeOfOldestMessage",namespace:"AWS/SQS"}}},presets:{highCpu:(e=80)=>({metricName:"CPUUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(e=80)=>({metricName:"MemoryUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(e=10)=>({metricName:"Errors",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(e=5000)=>({metricName:"Duration",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(e=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(e=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(e=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class J{static createUserPool(e){let{slug:t,environment:a,userPoolName:r,aliasAttributes:n,autoVerifiedAttributes:i,passwordPolicy:s,mfaConfiguration:o,emailConfiguration:c,smsConfiguration:l,lambdaTriggers:u,userPoolAddOns:m,accountRecoverySetting:p}=e,g=r||A({slug:t,environment:a,resourceType:"user-pool"}),h=f(g),y={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:g,Policies:s?{PasswordPolicy:{MinimumLength:s.minimumLength,RequireLowercase:s.requireLowercase,RequireUppercase:s.requireUppercase,RequireNumbers:s.requireNumbers,RequireSymbols:s.requireSymbols,TemporaryPasswordValidityDays:s.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:o,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(n&&n.length>0)y.Properties.UsernameAttributes=n;if(i&&i.length>0)y.Properties.AutoVerifiedAttributes=i;if(c)y.Properties.EmailConfiguration={EmailSendingAccount:c.emailSendingAccount,From:c.from,ReplyToEmailAddress:c.replyToEmailAddress,SourceArn:c.sourceArn,ConfigurationSet:c.configurationSet};if(l)y.Properties.SmsConfiguration={ExternalId:l.externalId,SnsCallerArn:l.snsCallerArn};if(u)y.Properties.LambdaConfig={PreSignUp:u.preSignUp,PostConfirmation:u.postConfirmation,PreAuthentication:u.preAuthentication,PostAuthentication:u.postAuthentication,CustomMessage:u.customMessage,DefineAuthChallenge:u.defineAuthChallenge,CreateAuthChallenge:u.createAuthChallenge,VerifyAuthChallengeResponse:u.verifyAuthChallengeResponse,PreTokenGeneration:u.preTokenGeneration,UserMigration:u.userMigration};if(m)y.Properties.UserPoolAddOns={AdvancedSecurityMode:m.advancedSecurityMode};if(p)y.Properties.AccountRecoverySetting={RecoveryMechanisms:p.recoveryMechanisms};return{userPool:y,logicalId:h}}static createUserPoolClient(e,t){let{slug:a,environment:r,clientName:n,generateSecret:i=!1,refreshTokenValidity:s,accessTokenValidity:o,idTokenValidity:c,tokenValidityUnits:l,readAttributes:u,writeAttributes:m,explicitAuthFlows:p,preventUserExistenceErrors:g,enableTokenRevocation:h,callbackURLs:y,logoutURLs:b,allowedOAuthFlows:T,allowedOAuthScopes:w,allowedOAuthFlowsUserPoolClient:S,supportedIdentityProviders:E}=t,v=n||A({slug:a,environment:r,resourceType:"user-pool-client"}),P=f(v);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:v,UserPoolId:C.Ref(e),GenerateSecret:i,RefreshTokenValidity:s,AccessTokenValidity:o,IdTokenValidity:c,TokenValidityUnits:l,ReadAttributes:u,WriteAttributes:m,ExplicitAuthFlows:p,PreventUserExistenceErrors:g,EnableTokenRevocation:h,CallbackURLs:y,LogoutURLs:b,AllowedOAuthFlows:T,AllowedOAuthScopes:w,AllowedOAuthFlowsUserPoolClient:S,SupportedIdentityProviders:E}},logicalId:P}}static createUserPoolDomain(e,t){let{slug:a,environment:r,domain:n,customDomainConfig:i}=t,s=A({slug:a,environment:r,resourceType:"user-pool-domain"}),o=f(s);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:n,UserPoolId:C.Ref(e),CustomDomainConfig:i}},logicalId:o}}static createIdentityPool(e){let{slug:t,environment:a,identityPoolName:r,allowUnauthenticatedIdentities:n=!1,cognitoIdentityProviders:i,supportedLoginProviders:s,samlProviderARNs:o,openIdConnectProviderARNs:c}=e,l=r||A({slug:t,environment:a,resourceType:"identity-pool"}),u=f(l);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:l,AllowUnauthenticatedIdentities:n,CognitoIdentityProviders:i,SupportedLoginProviders:s,SamlProviderARNs:o,OpenIdConnectProviderARNs:c}},logicalId:u}}static createIdentityPoolRoleAttachment(e,t){let{slug:a,environment:r,authenticatedRole:n,unauthenticatedRole:i,roleMappings:s}=t,o=A({slug:a,environment:r,resourceType:"identity-pool-role-attachment"}),c=f(o),l={authenticated:n};if(i)l.unauthenticated=i;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:C.Ref(e),Roles:l,RoleMappings:s}},logicalId:c}}static createAuthenticatedRole(e){let{slug:t,environment:a,identityPoolLogicalId:r}=e,n=A({slug:t,environment:a,resourceType:"cognito-authenticated-role"}),i=f(n);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:n,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":C.Ref(r)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"authenticated"}}}]},Policies:[{PolicyName:"CognitoAuthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*","cognito-identity:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:n},{Key:"Environment",Value:a}]}},logicalId:i}}static createUnauthenticatedRole(e){let{slug:t,environment:a,identityPoolLogicalId:r}=e,n=A({slug:t,environment:a,resourceType:"cognito-unauthenticated-role"}),i=f(n);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:n,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":C.Ref(r)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"unauthenticated"}}}]},Policies:[{PolicyName:"CognitoUnauthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:n},{Key:"Environment",Value:a}]}},logicalId:i}}static PasswordPolicies={relaxed:()=>({minimumLength:8,requireLowercase:!1,requireUppercase:!1,requireNumbers:!1,requireSymbols:!1,temporaryPasswordValidityDays:7}),standard:()=>({minimumLength:8,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!1,temporaryPasswordValidityDays:3}),strict:()=>({minimumLength:12,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!0,temporaryPasswordValidityDays:1})};static AuthFlows={standard:["ALLOW_USER_SRP_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],admin:["ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],custom:["ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],all:["ALLOW_USER_SRP_AUTH","ALLOW_USER_PASSWORD_AUTH","ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"]};static OAuthScopes={basic:["openid","email","profile"],all:["openid","email","profile","phone","aws.cognito.signin.user.admin"]};static UseCases={webApp:(e,t,a)=>{let{userPool:r,logicalId:n}=J.createUserPool({slug:e,environment:t,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:J.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:i,logicalId:s}=J.createUserPoolClient(n,{slug:e,environment:t,explicitAuthFlows:[...J.AuthFlows.standard],callbackURLs:[a],allowedOAuthFlows:["code"],allowedOAuthScopes:[...J.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:r,poolId:n,client:i,clientId:s}},mobileApp:(e,t)=>{let{userPool:a,logicalId:r}=J.createUserPool({slug:e,environment:t,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:J.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:n,logicalId:i}=J.createUserPoolClient(r,{slug:e,environment:t,explicitAuthFlows:[...J.AuthFlows.standard]}),{identityPool:s,logicalId:o}=J.createIdentityPool({slug:e,environment:t,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:C.Ref(i),ProviderName:C.GetAtt(r,"ProviderName")}]}),{role:c,logicalId:l}=J.createAuthenticatedRole({slug:e,environment:t,identityPoolLogicalId:o}),{attachment:u,logicalId:m}=J.createIdentityPoolRoleAttachment(o,{slug:e,environment:t,authenticatedRole:C.GetAtt(l,"Arn")});return{userPool:a,poolId:r,client:n,clientId:i,identityPool:s,identityPoolId:o,authRole:c,authRoleId:l,attachment:u,attachmentId:m}}}}class Q{static createApplication(e){let{slug:t,environment:a,applicationName:r,computePlatform:n}=e,i=r||A({slug:t,environment:a,resourceType:"deploy-app"}),s=f(i);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:i,ComputePlatform:n,Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:a}]}},logicalId:s}}static createDeploymentGroup(e,t){let{slug:a,environment:r,deploymentGroupName:n,serviceRoleArn:i,autoScalingGroups:s,ec2TagFilters:o,deploymentConfigName:c,autoRollbackConfiguration:l,alarmConfiguration:u,loadBalancerInfo:m,blueGreenDeploymentConfiguration:p}=t,g=n||A({slug:a,environment:r,resourceType:"deploy-group"}),h=f(g);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:C.Ref(e),DeploymentGroupName:g,ServiceRoleArn:i,AutoScalingGroups:s,Ec2TagFilters:o?.map((y)=>({Key:y.key,Value:y.value,Type:y.type})),DeploymentConfigName:c,AutoRollbackConfiguration:l?{Enabled:l.enabled,Events:l.events}:void 0,AlarmConfiguration:u?{Enabled:u.enabled,Alarms:u.alarms?.map((y)=>({Name:y.name})),IgnorePollAlarmFailure:u.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:m?{TargetGroupInfoList:m.targetGroupInfoList?.map((y)=>({Name:y.name})),ElbInfoList:m.elbInfoList?.map((y)=>({Name:y.name}))}:void 0,BlueGreenDeploymentConfiguration:p?{TerminateBlueInstancesOnDeploymentSuccess:p.terminateBlueInstancesOnDeploymentSuccess?{Action:p.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:p.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:p.deploymentReadyOption?{ActionOnTimeout:p.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:p.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:p.greenFleetProvisioningOption?{Action:p.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:r}]}},logicalId:h}}static createDeploymentConfig(e){let{slug:t,environment:a,deploymentConfigName:r,minimumHealthyHosts:n,trafficRoutingConfig:i}=e,s=r||A({slug:t,environment:a,resourceType:"deploy-config"}),o=f(s);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:s,MinimumHealthyHosts:n?{Type:n.type,Value:n.value}:void 0,TrafficRoutingConfig:i?{Type:i.type,TimeBasedCanary:i.timeBasedCanary?{CanaryPercentage:i.timeBasedCanary.canaryPercentage,CanaryInterval:i.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:i.timeBasedLinear?{LinearPercentage:i.timeBasedLinear.linearPercentage,LinearInterval:i.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:o}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(e,t)=>({type:e,value:t})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,t)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:t}}),linear:(e,t)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:t}})};static RollbackConfigs={onFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE"]}),onAlarmOrFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM"]}),onAllEvents:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM","DEPLOYMENT_STOP_ON_REQUEST"]}),disabled:()=>({enabled:!1})};static BlueGreenConfigs={standard:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withDelay:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:e},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withManualApproval:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"STOP_DEPLOYMENT",waitTimeInMinutes:e},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),keepBlue:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"KEEP_ALIVE"},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}})};static UseCases={ec2Deployment:(e,t,a,r)=>{let{application:n,logicalId:i}=Q.createApplication({slug:e,environment:t,computePlatform:"Server"}),{deploymentGroup:s,logicalId:o}=Q.createDeploymentGroup(i,{slug:e,environment:t,serviceRoleArn:a,autoScalingGroups:r,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:Q.RollbackConfigs.onFailure()});return{application:n,appId:i,deploymentGroup:s,groupId:o}},lambdaCanaryDeployment:(e,t,a,r=10,n=5)=>{let{application:i,logicalId:s}=Q.createApplication({slug:e,environment:t,computePlatform:"Lambda"}),{deploymentConfig:o,logicalId:c}=Q.createDeploymentConfig({slug:e,environment:t,trafficRoutingConfig:Q.TrafficRouting.canary(r,n)}),{deploymentGroup:l,logicalId:u}=Q.createDeploymentGroup(s,{slug:e,environment:t,serviceRoleArn:a,deploymentConfigName:C.Ref(c),autoRollbackConfiguration:Q.RollbackConfigs.onAlarmOrFailure()});return{application:i,appId:s,deploymentConfig:o,configId:c,deploymentGroup:l,groupId:u}},ecsBlueGreenDeployment:(e,t,a,r)=>{let{application:n,logicalId:i}=Q.createApplication({slug:e,environment:t,computePlatform:"ECS"}),{deploymentGroup:s,logicalId:o}=Q.createDeploymentGroup(i,{slug:e,environment:t,serviceRoleArn:a,loadBalancerInfo:{targetGroupInfoList:[{name:r}]},blueGreenDeploymentConfiguration:Q.BlueGreenConfigs.standard(),autoRollbackConfiguration:Q.RollbackConfigs.onFailure()});return{application:n,appId:i,deploymentGroup:s,groupId:o}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,t=5)=>({type:"canary",canaryPercentage:e,canaryInterval:t}),allAtOnce:()=>({type:"all-at-once"})}}class F{static ContentTypes={".html":"text/html",".htm":"text/html",".css":"text/css",".js":"application/javascript",".mjs":"application/javascript",".json":"application/json",".xml":"application/xml",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".otf":"font/otf",".eot":"application/vnd.ms-fontobject",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".map":"application/json"};static NoHashPatterns=[/^index\.html$/,/^favicon\.ico$/,/^robots\.txt$/,/^sitemap\.xml$/,/^manifest\.json$/,/^\.well-known\//,/^_redirects$/,/^_headers$/];static computeFileHash(e,t="md5"){let a=it(e);return Pi(t).update(a).digest("hex")}static computeShortHash(e){return F.computeFileHash(e).slice(0,8)}static getContentType(e){let t=ma(e).toLowerCase();return F.ContentTypes[t]||"application/octet-stream"}static shouldHashFile(e,t){return![...F.NoHashPatterns,...t||[]].some((a)=>a.test(e))}static generateHashedFilename(e,t){let a=ma(e),r=Di(e,a),n=da(e);if(n===".")return`${r}.${t}${a}`;return Ke(n,`${r}.${t}${a}`)}static collectFiles(e,t){let a=[],r=t||e;if(!Mt(e))return a;let n=Ri(e,{withFileTypes:!0});for(let i of n){let s=Ke(e,i.name);if(i.isDirectory())a.push(...F.collectFiles(s,r));else if(i.isFile())a.push(s)}return a}static hashDirectory(e){let{sourceDir:t,outputDir:a,excludePatterns:r=[],hashAlgorithm:n="md5",copyUnhashed:i=!0}=e,s=F.collectFiles(t),o=[],c={};for(let u of s){let m=u.replace(t,"").replace(/^[/\\]/,""),p=F.shouldHashFile(m,r),g=Ni(u),h=p?F.computeFileHash(u,n).slice(0,8):"",y=p?F.generateHashedFilename(m,h):m,b={originalPath:m,hashedPath:y,hash:h,size:g.size,contentType:F.getContentType(u)};if(o.push(b),c[m]=y,a){let T=Ke(a,y),w=da(T);if(!Mt(w)){let{mkdirSync:S}=_n("node:fs");S(w,{recursive:!0})}if(p||i)Ii(u,T)}}let l={version:"1.0",timestamp:new Date().toISOString(),assets:o,hashMap:c};if(a){let u=Ke(a,"asset-manifest.json");st(u,JSON.stringify(l,null,2))}return l}static getInvalidationPaths(e,t){let a=[];if(!e)return["/*"];let r=e.hashMap,n=t.hashMap;for(let[i,s]of Object.entries(n)){let o=r[i];if(!o||o!==s){if(a.push(`/${i}`),o&&o!==s)a.push(`/${o}`)}}for(let[i,s]of Object.entries(r))if(!n[i])a.push(`/${i}`),a.push(`/${s}`);if(a.length>100)return["/*"];return[...new Set(a)]}static updateHtmlReferences(e){let{htmlDir:t,manifest:a,basePath:r=""}=e,n=F.collectFiles(t).filter((i)=>i.endsWith(".html")||i.endsWith(".htm"));for(let i of n){let s=it(i,"utf-8");for(let[o,c]of Object.entries(a.hashMap)){if(o===c)continue;let l=[new RegExp(`(src|href)=["']${r}/?${F.escapeRegExp(o)}["']`,"g"),new RegExp(`url\\(["']?${r}/?${F.escapeRegExp(o)}["']?\\)`,"g")];for(let u of l)s=s.replace(u,(m)=>{return m.replace(o,c)})}st(i,s)}}static updateCssReferences(e){let{cssDir:t,manifest:a,basePath:r=""}=e,n=F.collectFiles(t).filter((i)=>i.endsWith(".css"));for(let i of n){let s=it(i,"utf-8");for(let[o,c]of Object.entries(a.hashMap)){if(o===c)continue;let l=new RegExp(`url\\(["']?${r}/?${F.escapeRegExp(o)}["']?\\)`,"g");s=s.replace(l,`url(${r}/${c})`)}st(i,s)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:t,keyPrefix:a="",excludePatterns:r=[],cacheControl:n={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return F.hashDirectory({sourceDir:t,excludePatterns:r}).assets.map((i)=>{let s=i.hash!=="",o=i.contentType==="text/html",c=n.unhashed||"public, max-age=3600";if(o)c=n.html||"public, max-age=0, must-revalidate";else if(s)c=n.hashed||"public, max-age=31536000, immutable";return{localPath:Ke(t,i.originalPath),s3Key:a?`${a}/${i.hashedPath}`:i.hashedPath,contentType:i.contentType,cacheControl:c,hash:i.hash}})}static compareManifests(e,t){let a={added:[],removed:[],changed:[],unchanged:[]},r=new Set(Object.keys(e.hashMap)),n=new Set(Object.keys(t.hashMap));for(let i of n)if(!r.has(i))a.added.push(i);for(let i of r)if(!n.has(i))a.removed.push(i);for(let i of n)if(r.has(i))if(e.hashMap[i]!==t.hashMap[i])a.changed.push(i);else a.unchanged.push(i);return a}static loadManifest(e){if(!Mt(e))return null;try{let t=it(e,"utf-8");return JSON.parse(t)}catch{return null}}static saveManifest(e,t){st(t,JSON.stringify(e,null,2))}}class ze{static createSecret(e){let{slug:t,environment:a,secretName:r,description:n,secretString:i,kmsKeyId:s,tags:o}=e,c=r||A({slug:t,environment:a,resourceType:"secret"}),l=f(c),u={Type:"AWS::SecretsManager::Secret",Properties:{Name:c,Description:n,SecretString:i,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:a},...o?Object.entries(o).map(([m,p])=>({Key:m,Value:p})):[]]}};if(s)u.Properties.KmsKeyId=s;return{secret:u,logicalId:l}}static createGeneratedSecret(e){let{slug:t,environment:a,secretName:r,description:n,excludeCharacters:i,excludeLowercase:s,excludeNumbers:o,excludePunctuation:c,excludeUppercase:l,passwordLength:u,requireEachIncludedType:m,kmsKeyId:p,tags:g}=e,h=r||A({slug:t,environment:a,resourceType:"secret"}),y=f(h),b={Type:"AWS::SecretsManager::Secret",Properties:{Name:h,Description:n,GenerateSecretString:{ExcludeCharacters:i,ExcludeLowercase:s,ExcludeNumbers:o,ExcludePunctuation:c,ExcludeUppercase:l,PasswordLength:u||32,RequireEachIncludedType:m!==!1},Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:a},...g?Object.entries(g).map(([T,w])=>({Key:T,Value:w})):[]]}};if(p)b.Properties.KmsKeyId=p;return{secret:b,logicalId:y}}static createDatabaseSecret(e){let{slug:t,environment:a,secretName:r,username:n,dbname:i,engine:s,host:o,port:c,kmsKeyId:l}=e,u=r||A({slug:t,environment:a,resourceType:"db-secret"}),m=f(u),p={username:n};if(i)p.dbname=i;if(s)p.engine=s;if(o)p.host=o;if(c)p.port=c;let g={Type:"AWS::SecretsManager::Secret",Properties:{Name:u,Description:`Database credentials for ${n}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(p),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:a},{Key:"Type",Value:"database"}]}};if(l)g.Properties.KmsKeyId=l;return{secret:g,logicalId:m}}static attachToDatabase(e){let{slug:t,environment:a,secretId:r,targetId:n,targetType:i}=e,s=A({slug:t,environment:a,resourceType:"secret-attachment"}),o=f(s);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:r,TargetId:n,TargetType:i}},logicalId:o}}static enableRotation(e){let{slug:t,environment:a,secretId:r,rotationLambdaArn:n,automaticallyAfterDays:i,rotationType:s,kmsKeyArn:o,vpcSecurityGroupIds:c,vpcSubnetIds:l}=e,u=A({slug:t,environment:a,resourceType:"secret-rotation"}),m=f(u),p={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:r,RotationRules:{AutomaticallyAfterDays:i||30}}};if(n)p.Properties.RotationLambdaARN=n;else if(s)p.Properties.HostedRotationLambda={RotationType:s,KmsKeyArn:o,VpcSecurityGroupIds:c,VpcSubnetIds:l};return{rotation:p,logicalId:m}}static SecretTypes={apiKey:(e,t,a)=>{return ze.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-${a}-api-key`,description:`API key for ${a}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1})},oauthClientSecret:(e,t,a)=>{return ze.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-${a}-oauth-secret`,description:`OAuth client secret for ${a}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0})},jwtSecret:(e,t)=>{return ze.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0})},encryptionKey:(e,t)=>{return ze.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-encryption-key`,description:"Data encryption key",passwordLength:64,excludeCharacters:"+/=",excludePunctuation:!0})}};static RotationTypes={MySQLSingleUser:"MySQLSingleUser",MySQLMultiUser:"MySQLMultiUser",PostgreSQLSingleUser:"PostgreSQLSingleUser",PostgreSQLMultiUser:"PostgreSQLMultiUser",OracleSingleUser:"OracleSingleUser",OracleMultiUser:"OracleMultiUser",MariaDBSingleUser:"MariaDBSingleUser",MariaDBMultiUser:"MariaDBMultiUser",SQLServerSingleUser:"SQLServerSingleUser",SQLServerMultiUser:"SQLServerMultiUser",RedshiftSingleUser:"RedshiftSingleUser",RedshiftMultiUser:"RedshiftMultiUser",MongoDBSingleUser:"MongoDBSingleUser",MongoDBMultiUser:"MongoDBMultiUser"}}class B{static createParameter(e){let{slug:t,environment:a,parameterName:r,value:n,type:i="String",description:s,tier:o="Standard",tags:c}=e,l=r||A({slug:t,environment:a,resourceType:"parameter"}),u=f(l);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${t}/${a}/${l}`,Type:i,Value:n,Description:s,Tier:o,Tags:{Name:l,Environment:a,...c}}},logicalId:u}}static createString(e,t,a,r,n){return B.createParameter({slug:e,environment:t,parameterName:a,value:r,type:"String",description:n})}static createSecureString(e,t,a,r,n){return B.createParameter({slug:e,environment:t,parameterName:a,value:r,type:"SecureString",description:n})}static createStringList(e,t,a,r,n){return B.createParameter({slug:e,environment:t,parameterName:a,value:r.join(","),type:"StringList",description:n})}static Parameters={databaseUrl:(e,t,a)=>{return B.createSecureString(e,t,"database-url",a,"Database connection URL")},apiEndpoint:(e,t,a)=>{return B.createString(e,t,"api-endpoint",a,"API endpoint URL")},appVersion:(e,t,a)=>{return B.createString(e,t,"app-version",a,"Application version")},featureFlags:(e,t,a)=>{return B.createStringList(e,t,"feature-flags",a,"Enabled feature flags")},apiKey:(e,t,a,r)=>{return B.createSecureString(e,t,`${a}-api-key`,r,`API key for ${a}`)},oauthCredentials:(e,t,a,r)=>{let n=B.createString(e,t,"oauth-client-id",a,"OAuth client ID"),i=B.createSecureString(e,t,"oauth-client-secret",r,"OAuth client secret");return{clientId:n,clientSecret:i}},smtpCredentials:(e,t,a,r,n,i)=>{let s=B.createString(e,t,"smtp-username",a,"SMTP username"),o=B.createSecureString(e,t,"smtp-password",r,"SMTP password"),c=B.createString(e,t,"smtp-host",n,"SMTP host"),l=B.createString(e,t,"smtp-port",i.toString(),"SMTP port");return{username:s,password:o,host:c,port:l}},redisUrl:(e,t,a)=>{return B.createSecureString(e,t,"redis-url",a,"Redis connection URL")},s3Bucket:(e,t,a)=>{return B.createString(e,t,"s3-bucket",a,"S3 bucket name")},cloudFrontDistribution:(e,t,a)=>{return B.createString(e,t,"cloudfront-distribution-id",a,"CloudFront distribution ID")}}}class Je{static createDomain(e){let{slug:t,environment:a,domainName:r,engineVersion:n="OpenSearch_2.11",instanceType:i="t3.small.search",instanceCount:s=1,volumeSize:o=10,volumeType:c="gp3",dedicatedMaster:l=!1,dedicatedMasterType:u,dedicatedMasterCount:m=3,multiAz:p=!1,availabilityZoneCount:g=2,vpc:h,encryption:y,enforceHttps:b=!0,tlsSecurityPolicy:T="Policy-Min-TLS-1-2-2019-07",advancedSecurity:w,autoSnapshotHour:S=0,autoTune:E=!0,tags:v={}}=e,P=r||A({slug:t,environment:a,resourceType:"search"}),N=f(P);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:P,EngineVersion:n,ClusterConfig:{InstanceType:i,InstanceCount:s,DedicatedMasterEnabled:l,...l&&{DedicatedMasterType:u||i,DedicatedMasterCount:m},ZoneAwarenessEnabled:p,...p&&{ZoneAwarenessConfig:{AvailabilityZoneCount:g}}},EBSOptions:{EBSEnabled:!0,VolumeType:c,VolumeSize:o},DomainEndpointOptions:{EnforceHTTPS:b,TLSSecurityPolicy:T},SnapshotOptions:{AutomatedSnapshotStartHour:S},...h&&{VPCOptions:{SubnetIds:h.subnetIds,SecurityGroupIds:h.securityGroupIds}},...y&&{EncryptionAtRestOptions:{Enabled:y.atRest??!0,...y.kmsKeyId&&{KmsKeyId:y.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:y.nodeToNode??!0}},...w&&{AdvancedSecurityOptions:{Enabled:w.enabled,InternalUserDatabaseEnabled:w.internalUserDatabase??!0,...w.masterUserName&&w.masterUserPassword&&{MasterUserOptions:{MasterUserName:w.masterUserName,MasterUserPassword:w.masterUserPassword}},...w.masterUserArn&&{MasterUserOptions:{MasterUserARN:w.masterUserArn}}}},...E&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:a},...Object.entries(v).map(([I,D])=>({Key:I,Value:D}))]}},logicalId:N}}static createAccessPolicy(e,t){let{ipAddresses:a,iamPrincipalArns:r,allowAll:n,vpcEndpoint:i}=t;if(n)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let s=[];if(r&&r.length>0)s.push({Effect:"Allow",Principal:{AWS:r},Action:"es:*",Resource:e});if(a&&a.length>0)s.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e,Condition:{IpAddress:{"aws:SourceIp":a}}});if(i)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};return{Version:"2012-10-17",Statement:s}}static DomainPresets={development:(e,t)=>{return Je.createDomain({slug:e,environment:t,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1})},production:(e,t,a)=>{return Je.createDomain({slug:e,environment:t,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:a,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0})},costOptimized:(e,t)=>{return Je.createDomain({slug:e,environment:t,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0})},highPerformance:(e,t,a)=>{return Je.createDomain({slug:e,environment:t,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:a,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 dt{static createDomainRedirectBucket(e){let{slug:t,environment:a,sourceDomain:r,targetDomain:n,protocol:i="https"}=e,s=A({slug:t,environment:a,resourceType:"s3",suffix:"redirect"}),o=f(s),c=f(`${s}-policy`),l={Type:"AWS::S3::Bucket",Properties:{BucketName:r,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:n,Protocol:i}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:a},{Key:"Purpose",Value:"Domain Redirect"}]}},u={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:C.Ref(o),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[C.Join("",[C.GetAtt(o,"Arn"),"/*"])]}]}}};return{bucket:l,bucketPolicy:u,logicalId:o,policyLogicalId:c}}static createPathRedirectFunction(e){let{slug:t,environment:a,rules:r}=e,n=A({slug:t,environment:a,resourceType:"cf-redirect"}),i=f(n),s=dt.generateRedirectFunctionCode(r);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:n,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${t} (${a})`,Runtime:"cloudfront-js-2.0"},FunctionCode:s}},logicalId:i,functionCode:s}}static generateRedirectFunctionCode(e){return`function handler(event) {
|
|
2316
|
+
| limit 50`,region:r,title:"Recent Errors and Warnings"}}),s+=6;return Ha.createDashboard({slug:t,environment:a,widgets:i})}static DashboardTemplates={staticWebsite:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Static Website Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"CloudFront Requests",region:"us-east-1",metrics:[["AWS/CloudFront","Requests","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"Error Rate",region:"us-east-1",metrics:[["AWS/CloudFront","4xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"5XX"}]],period:300,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Bytes Downloaded",region:"us-east-1",metrics:[["AWS/CloudFront","BytesDownloaded","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:e.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",e.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:e.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",e.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",e.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",e.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",e.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",e.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...e.lambdaFunctionNames.map((t,a)=>({type:"metric",x:a%3*8,y:7+Math.floor(a/3)*6,width:8,height:6,properties:{title:`${t} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",t],["AWS/Lambda","Duration","FunctionName",t],["AWS/Lambda","Errors","FunctionName",t]],period:300,stat:"Sum"}}))]}),containerService:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Container Service Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"ECS CPU",region:e.region||"us-east-1",metrics:[["AWS/ECS","CPUUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"ECS Memory",region:e.region||"us-east-1",metrics:[["AWS/ECS","MemoryUtilization","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Running Tasks",region:e.region||"us-east-1",metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",e.ecsClusterName,"ServiceName",e.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:0,y:7,width:8,height:6,properties:{title:"ALB Requests",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",e.albName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:7,width:8,height:6,properties:{title:"Response Time",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",e.albName]],period:60,stat:"Average"}},{type:"metric",x:16,y:7,width:8,height:6,properties:{title:"Healthy Hosts",region:e.region||"us-east-1",metrics:[["AWS/ApplicationELB","HealthyHostCount","LoadBalancer",e.albName]],period:60,stat:"Average"}},...e.rdsInstanceId?[{type:"metric",x:0,y:13,width:12,height:6,properties:{title:"RDS CPU",region:e.region||"us-east-1",metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",e.rdsInstanceId]],period:300,stat:"Average"}},{type:"metric",x:12,y:13,width:12,height:6,properties:{title:"RDS Connections",region:e.region||"us-east-1",metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",e.rdsInstanceId]],period:60,stat:"Sum"}}]:[]]})};static Config={createAlarmConfig:(e)=>{let{metricName:t,namespace:a,threshold:r,comparisonOperator:n="GreaterThanThreshold",evaluationPeriods:i=1,period:s=300,statistic:o="Average",treatMissingData:c="missing"}=e;return{MetricName:t,Namespace:a,Threshold:r,ComparisonOperator:n,EvaluationPeriods:i,Period:s,Statistic:o,TreatMissingData:c}},namespaces:{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",sqs:"AWS/SQS",sns:"AWS/SNS",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apiGateway:"AWS/ApiGateway",dynamodb:"AWS/DynamoDB",elasticache:"AWS/ElastiCache"},comparisonOperators:{greaterThan:"GreaterThanThreshold",greaterOrEqual:"GreaterThanOrEqualToThreshold",lessThan:"LessThanThreshold",lessOrEqual:"LessThanOrEqualToThreshold"},metrics:{ec2:{cpu:{metricName:"CPUUtilization",namespace:"AWS/EC2"},networkIn:{metricName:"NetworkIn",namespace:"AWS/EC2"},networkOut:{metricName:"NetworkOut",namespace:"AWS/EC2"},statusCheck:{metricName:"StatusCheckFailed",namespace:"AWS/EC2"}},ecs:{cpu:{metricName:"CPUUtilization",namespace:"AWS/ECS"},memory:{metricName:"MemoryUtilization",namespace:"AWS/ECS"}},lambda:{invocations:{metricName:"Invocations",namespace:"AWS/Lambda"},errors:{metricName:"Errors",namespace:"AWS/Lambda"},duration:{metricName:"Duration",namespace:"AWS/Lambda"},throttles:{metricName:"Throttles",namespace:"AWS/Lambda"},concurrentExecutions:{metricName:"ConcurrentExecutions",namespace:"AWS/Lambda"}},rds:{cpu:{metricName:"CPUUtilization",namespace:"AWS/RDS"},connections:{metricName:"DatabaseConnections",namespace:"AWS/RDS"},freeStorage:{metricName:"FreeStorageSpace",namespace:"AWS/RDS"},readLatency:{metricName:"ReadLatency",namespace:"AWS/RDS"},writeLatency:{metricName:"WriteLatency",namespace:"AWS/RDS"}},alb:{requestCount:{metricName:"RequestCount",namespace:"AWS/ApplicationELB"},responseTime:{metricName:"TargetResponseTime",namespace:"AWS/ApplicationELB"},httpCode4xx:{metricName:"HTTPCode_Target_4XX_Count",namespace:"AWS/ApplicationELB"},httpCode5xx:{metricName:"HTTPCode_Target_5XX_Count",namespace:"AWS/ApplicationELB"},healthyHosts:{metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB"}},sqs:{messagesVisible:{metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS"},messagesDelayed:{metricName:"ApproximateNumberOfMessagesDelayed",namespace:"AWS/SQS"},messageAge:{metricName:"ApproximateAgeOfOldestMessage",namespace:"AWS/SQS"}}},presets:{highCpu:(e=80)=>({metricName:"CPUUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(e=80)=>({metricName:"MemoryUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(e=10)=>({metricName:"Errors",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(e=5000)=>({metricName:"Duration",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(e=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(e=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(e=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class Q{static createUserPool(e){let{slug:t,environment:a,userPoolName:r,aliasAttributes:n,autoVerifiedAttributes:i,passwordPolicy:s,mfaConfiguration:o,emailConfiguration:c,smsConfiguration:l,lambdaTriggers:u,userPoolAddOns:m,accountRecoverySetting:p}=e,g=r||A({slug:t,environment:a,resourceType:"user-pool"}),h=f(g),y={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:g,Policies:s?{PasswordPolicy:{MinimumLength:s.minimumLength,RequireLowercase:s.requireLowercase,RequireUppercase:s.requireUppercase,RequireNumbers:s.requireNumbers,RequireSymbols:s.requireSymbols,TemporaryPasswordValidityDays:s.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:o,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(n&&n.length>0)y.Properties.UsernameAttributes=n;if(i&&i.length>0)y.Properties.AutoVerifiedAttributes=i;if(c)y.Properties.EmailConfiguration={EmailSendingAccount:c.emailSendingAccount,From:c.from,ReplyToEmailAddress:c.replyToEmailAddress,SourceArn:c.sourceArn,ConfigurationSet:c.configurationSet};if(l)y.Properties.SmsConfiguration={ExternalId:l.externalId,SnsCallerArn:l.snsCallerArn};if(u)y.Properties.LambdaConfig={PreSignUp:u.preSignUp,PostConfirmation:u.postConfirmation,PreAuthentication:u.preAuthentication,PostAuthentication:u.postAuthentication,CustomMessage:u.customMessage,DefineAuthChallenge:u.defineAuthChallenge,CreateAuthChallenge:u.createAuthChallenge,VerifyAuthChallengeResponse:u.verifyAuthChallengeResponse,PreTokenGeneration:u.preTokenGeneration,UserMigration:u.userMigration};if(m)y.Properties.UserPoolAddOns={AdvancedSecurityMode:m.advancedSecurityMode};if(p)y.Properties.AccountRecoverySetting={RecoveryMechanisms:p.recoveryMechanisms};return{userPool:y,logicalId:h}}static createUserPoolClient(e,t){let{slug:a,environment:r,clientName:n,generateSecret:i=!1,refreshTokenValidity:s,accessTokenValidity:o,idTokenValidity:c,tokenValidityUnits:l,readAttributes:u,writeAttributes:m,explicitAuthFlows:p,preventUserExistenceErrors:g,enableTokenRevocation:h,callbackURLs:y,logoutURLs:b,allowedOAuthFlows:T,allowedOAuthScopes:w,allowedOAuthFlowsUserPoolClient:S,supportedIdentityProviders:E}=t,v=n||A({slug:a,environment:r,resourceType:"user-pool-client"}),P=f(v);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:v,UserPoolId:C.Ref(e),GenerateSecret:i,RefreshTokenValidity:s,AccessTokenValidity:o,IdTokenValidity:c,TokenValidityUnits:l,ReadAttributes:u,WriteAttributes:m,ExplicitAuthFlows:p,PreventUserExistenceErrors:g,EnableTokenRevocation:h,CallbackURLs:y,LogoutURLs:b,AllowedOAuthFlows:T,AllowedOAuthScopes:w,AllowedOAuthFlowsUserPoolClient:S,SupportedIdentityProviders:E}},logicalId:P}}static createUserPoolDomain(e,t){let{slug:a,environment:r,domain:n,customDomainConfig:i}=t,s=A({slug:a,environment:r,resourceType:"user-pool-domain"}),o=f(s);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:n,UserPoolId:C.Ref(e),CustomDomainConfig:i}},logicalId:o}}static createIdentityPool(e){let{slug:t,environment:a,identityPoolName:r,allowUnauthenticatedIdentities:n=!1,cognitoIdentityProviders:i,supportedLoginProviders:s,samlProviderARNs:o,openIdConnectProviderARNs:c}=e,l=r||A({slug:t,environment:a,resourceType:"identity-pool"}),u=f(l);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:l,AllowUnauthenticatedIdentities:n,CognitoIdentityProviders:i,SupportedLoginProviders:s,SamlProviderARNs:o,OpenIdConnectProviderARNs:c}},logicalId:u}}static createIdentityPoolRoleAttachment(e,t){let{slug:a,environment:r,authenticatedRole:n,unauthenticatedRole:i,roleMappings:s}=t,o=A({slug:a,environment:r,resourceType:"identity-pool-role-attachment"}),c=f(o),l={authenticated:n};if(i)l.unauthenticated=i;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:C.Ref(e),Roles:l,RoleMappings:s}},logicalId:c}}static createAuthenticatedRole(e){let{slug:t,environment:a,identityPoolLogicalId:r}=e,n=A({slug:t,environment:a,resourceType:"cognito-authenticated-role"}),i=f(n);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:n,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":C.Ref(r)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"authenticated"}}}]},Policies:[{PolicyName:"CognitoAuthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*","cognito-identity:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:n},{Key:"Environment",Value:a}]}},logicalId:i}}static createUnauthenticatedRole(e){let{slug:t,environment:a,identityPoolLogicalId:r}=e,n=A({slug:t,environment:a,resourceType:"cognito-unauthenticated-role"}),i=f(n);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:n,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":C.Ref(r)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"unauthenticated"}}}]},Policies:[{PolicyName:"CognitoUnauthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:n},{Key:"Environment",Value:a}]}},logicalId:i}}static PasswordPolicies={relaxed:()=>({minimumLength:8,requireLowercase:!1,requireUppercase:!1,requireNumbers:!1,requireSymbols:!1,temporaryPasswordValidityDays:7}),standard:()=>({minimumLength:8,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!1,temporaryPasswordValidityDays:3}),strict:()=>({minimumLength:12,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!0,temporaryPasswordValidityDays:1})};static AuthFlows={standard:["ALLOW_USER_SRP_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],admin:["ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],custom:["ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],all:["ALLOW_USER_SRP_AUTH","ALLOW_USER_PASSWORD_AUTH","ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"]};static OAuthScopes={basic:["openid","email","profile"],all:["openid","email","profile","phone","aws.cognito.signin.user.admin"]};static UseCases={webApp:(e,t,a)=>{let{userPool:r,logicalId:n}=Q.createUserPool({slug:e,environment:t,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Q.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:i,logicalId:s}=Q.createUserPoolClient(n,{slug:e,environment:t,explicitAuthFlows:[...Q.AuthFlows.standard],callbackURLs:[a],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Q.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:r,poolId:n,client:i,clientId:s}},mobileApp:(e,t)=>{let{userPool:a,logicalId:r}=Q.createUserPool({slug:e,environment:t,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Q.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:n,logicalId:i}=Q.createUserPoolClient(r,{slug:e,environment:t,explicitAuthFlows:[...Q.AuthFlows.standard]}),{identityPool:s,logicalId:o}=Q.createIdentityPool({slug:e,environment:t,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:C.Ref(i),ProviderName:C.GetAtt(r,"ProviderName")}]}),{role:c,logicalId:l}=Q.createAuthenticatedRole({slug:e,environment:t,identityPoolLogicalId:o}),{attachment:u,logicalId:m}=Q.createIdentityPoolRoleAttachment(o,{slug:e,environment:t,authenticatedRole:C.GetAtt(l,"Arn")});return{userPool:a,poolId:r,client:n,clientId:i,identityPool:s,identityPoolId:o,authRole:c,authRoleId:l,attachment:u,attachmentId:m}}}}class J{static createApplication(e){let{slug:t,environment:a,applicationName:r,computePlatform:n}=e,i=r||A({slug:t,environment:a,resourceType:"deploy-app"}),s=f(i);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:i,ComputePlatform:n,Tags:[{Key:"Name",Value:i},{Key:"Environment",Value:a}]}},logicalId:s}}static createDeploymentGroup(e,t){let{slug:a,environment:r,deploymentGroupName:n,serviceRoleArn:i,autoScalingGroups:s,ec2TagFilters:o,deploymentConfigName:c,autoRollbackConfiguration:l,alarmConfiguration:u,loadBalancerInfo:m,blueGreenDeploymentConfiguration:p}=t,g=n||A({slug:a,environment:r,resourceType:"deploy-group"}),h=f(g);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:C.Ref(e),DeploymentGroupName:g,ServiceRoleArn:i,AutoScalingGroups:s,Ec2TagFilters:o?.map((y)=>({Key:y.key,Value:y.value,Type:y.type})),DeploymentConfigName:c,AutoRollbackConfiguration:l?{Enabled:l.enabled,Events:l.events}:void 0,AlarmConfiguration:u?{Enabled:u.enabled,Alarms:u.alarms?.map((y)=>({Name:y.name})),IgnorePollAlarmFailure:u.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:m?{TargetGroupInfoList:m.targetGroupInfoList?.map((y)=>({Name:y.name})),ElbInfoList:m.elbInfoList?.map((y)=>({Name:y.name}))}:void 0,BlueGreenDeploymentConfiguration:p?{TerminateBlueInstancesOnDeploymentSuccess:p.terminateBlueInstancesOnDeploymentSuccess?{Action:p.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:p.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:p.deploymentReadyOption?{ActionOnTimeout:p.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:p.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:p.greenFleetProvisioningOption?{Action:p.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:r}]}},logicalId:h}}static createDeploymentConfig(e){let{slug:t,environment:a,deploymentConfigName:r,minimumHealthyHosts:n,trafficRoutingConfig:i}=e,s=r||A({slug:t,environment:a,resourceType:"deploy-config"}),o=f(s);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:s,MinimumHealthyHosts:n?{Type:n.type,Value:n.value}:void 0,TrafficRoutingConfig:i?{Type:i.type,TimeBasedCanary:i.timeBasedCanary?{CanaryPercentage:i.timeBasedCanary.canaryPercentage,CanaryInterval:i.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:i.timeBasedLinear?{LinearPercentage:i.timeBasedLinear.linearPercentage,LinearInterval:i.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:o}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(e,t)=>({type:e,value:t})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,t)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:t}}),linear:(e,t)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:t}})};static RollbackConfigs={onFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE"]}),onAlarmOrFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM"]}),onAllEvents:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM","DEPLOYMENT_STOP_ON_REQUEST"]}),disabled:()=>({enabled:!1})};static BlueGreenConfigs={standard:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withDelay:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:e},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withManualApproval:(e)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"STOP_DEPLOYMENT",waitTimeInMinutes:e},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),keepBlue:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"KEEP_ALIVE"},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}})};static UseCases={ec2Deployment:(e,t,a,r)=>{let{application:n,logicalId:i}=J.createApplication({slug:e,environment:t,computePlatform:"Server"}),{deploymentGroup:s,logicalId:o}=J.createDeploymentGroup(i,{slug:e,environment:t,serviceRoleArn:a,autoScalingGroups:r,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:J.RollbackConfigs.onFailure()});return{application:n,appId:i,deploymentGroup:s,groupId:o}},lambdaCanaryDeployment:(e,t,a,r=10,n=5)=>{let{application:i,logicalId:s}=J.createApplication({slug:e,environment:t,computePlatform:"Lambda"}),{deploymentConfig:o,logicalId:c}=J.createDeploymentConfig({slug:e,environment:t,trafficRoutingConfig:J.TrafficRouting.canary(r,n)}),{deploymentGroup:l,logicalId:u}=J.createDeploymentGroup(s,{slug:e,environment:t,serviceRoleArn:a,deploymentConfigName:C.Ref(c),autoRollbackConfiguration:J.RollbackConfigs.onAlarmOrFailure()});return{application:i,appId:s,deploymentConfig:o,configId:c,deploymentGroup:l,groupId:u}},ecsBlueGreenDeployment:(e,t,a,r)=>{let{application:n,logicalId:i}=J.createApplication({slug:e,environment:t,computePlatform:"ECS"}),{deploymentGroup:s,logicalId:o}=J.createDeploymentGroup(i,{slug:e,environment:t,serviceRoleArn:a,loadBalancerInfo:{targetGroupInfoList:[{name:r}]},blueGreenDeploymentConfiguration:J.BlueGreenConfigs.standard(),autoRollbackConfiguration:J.RollbackConfigs.onFailure()});return{application:n,appId:i,deploymentGroup:s,groupId:o}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,t=5)=>({type:"canary",canaryPercentage:e,canaryInterval:t}),allAtOnce:()=>({type:"all-at-once"})}}class U{static ContentTypes={".html":"text/html",".htm":"text/html",".css":"text/css",".js":"application/javascript",".mjs":"application/javascript",".json":"application/json",".xml":"application/xml",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".otf":"font/otf",".eot":"application/vnd.ms-fontobject",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".map":"application/json"};static NoHashPatterns=[/^index\.html$/,/^favicon\.ico$/,/^robots\.txt$/,/^sitemap\.xml$/,/^manifest\.json$/,/^\.well-known\//,/^_redirects$/,/^_headers$/];static computeFileHash(e,t="md5"){let a=st(e);return Ii(t).update(a).digest("hex")}static computeShortHash(e){return U.computeFileHash(e).slice(0,8)}static getContentType(e){let t=pa(e).toLowerCase();return U.ContentTypes[t]||"application/octet-stream"}static shouldHashFile(e,t){return![...U.NoHashPatterns,...t||[]].some((a)=>a.test(e))}static generateHashedFilename(e,t){let a=pa(e),r=ki(e,a),n=ma(e);if(n===".")return`${r}.${t}${a}`;return Ke(n,`${r}.${t}${a}`)}static collectFiles(e,t){let a=[],r=t||e;if(!Lt(e))return a;let n=Ni(e,{withFileTypes:!0});for(let i of n){let s=Ke(e,i.name);if(i.isDirectory())a.push(...U.collectFiles(s,r));else if(i.isFile())a.push(s)}return a}static hashDirectory(e){let{sourceDir:t,outputDir:a,excludePatterns:r=[],hashAlgorithm:n="md5",copyUnhashed:i=!0}=e,s=U.collectFiles(t),o=[],c={};for(let u of s){let m=u.replace(t,"").replace(/^[/\\]/,""),p=U.shouldHashFile(m,r),g=Di(u),h=p?U.computeFileHash(u,n).slice(0,8):"",y=p?U.generateHashedFilename(m,h):m,b={originalPath:m,hashedPath:y,hash:h,size:g.size,contentType:U.getContentType(u)};if(o.push(b),c[m]=y,a){let T=Ke(a,y),w=ma(T);if(!Lt(w)){let{mkdirSync:S}=_n("node:fs");S(w,{recursive:!0})}if(p||i)Ri(u,T)}}let l={version:"1.0",timestamp:new Date().toISOString(),assets:o,hashMap:c};if(a){let u=Ke(a,"asset-manifest.json");ot(u,JSON.stringify(l,null,2))}return l}static getInvalidationPaths(e,t){let a=[];if(!e)return["/*"];let r=e.hashMap,n=t.hashMap;for(let[i,s]of Object.entries(n)){let o=r[i];if(!o||o!==s){if(a.push(`/${i}`),o&&o!==s)a.push(`/${o}`)}}for(let[i,s]of Object.entries(r))if(!n[i])a.push(`/${i}`),a.push(`/${s}`);if(a.length>100)return["/*"];return[...new Set(a)]}static updateHtmlReferences(e){let{htmlDir:t,manifest:a,basePath:r=""}=e,n=U.collectFiles(t).filter((i)=>i.endsWith(".html")||i.endsWith(".htm"));for(let i of n){let s=st(i,"utf-8");for(let[o,c]of Object.entries(a.hashMap)){if(o===c)continue;let l=[new RegExp(`(src|href)=["']${r}/?${U.escapeRegExp(o)}["']`,"g"),new RegExp(`url\\(["']?${r}/?${U.escapeRegExp(o)}["']?\\)`,"g")];for(let u of l)s=s.replace(u,(m)=>m.replace(o,c))}ot(i,s)}}static updateCssReferences(e){let{cssDir:t,manifest:a,basePath:r=""}=e,n=U.collectFiles(t).filter((i)=>i.endsWith(".css"));for(let i of n){let s=st(i,"utf-8");for(let[o,c]of Object.entries(a.hashMap)){if(o===c)continue;let l=new RegExp(`url\\(["']?${r}/?${U.escapeRegExp(o)}["']?\\)`,"g");s=s.replace(l,`url(${r}/${c})`)}ot(i,s)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:t,keyPrefix:a="",excludePatterns:r=[],cacheControl:n={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return U.hashDirectory({sourceDir:t,excludePatterns:r}).assets.map((i)=>{let s=i.hash!=="",o=i.contentType==="text/html",c=n.unhashed||"public, max-age=3600";if(o)c=n.html||"public, max-age=0, must-revalidate";else if(s)c=n.hashed||"public, max-age=31536000, immutable";return{localPath:Ke(t,i.originalPath),s3Key:a?`${a}/${i.hashedPath}`:i.hashedPath,contentType:i.contentType,cacheControl:c,hash:i.hash}})}static compareManifests(e,t){let a={added:[],removed:[],changed:[],unchanged:[]},r=new Set(Object.keys(e.hashMap)),n=new Set(Object.keys(t.hashMap));for(let i of n)if(!r.has(i))a.added.push(i);for(let i of r)if(!n.has(i))a.removed.push(i);for(let i of n)if(r.has(i))if(e.hashMap[i]!==t.hashMap[i])a.changed.push(i);else a.unchanged.push(i);return a}static loadManifest(e){if(!Lt(e))return null;try{let t=st(e,"utf-8");return JSON.parse(t)}catch{return null}}static saveManifest(e,t){ot(t,JSON.stringify(e,null,2))}}class ze{static createSecret(e){let{slug:t,environment:a,secretName:r,description:n,secretString:i,kmsKeyId:s,tags:o}=e,c=r||A({slug:t,environment:a,resourceType:"secret"}),l=f(c),u={Type:"AWS::SecretsManager::Secret",Properties:{Name:c,Description:n,SecretString:i,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:a},...o?Object.entries(o).map(([m,p])=>({Key:m,Value:p})):[]]}};if(s)u.Properties.KmsKeyId=s;return{secret:u,logicalId:l}}static createGeneratedSecret(e){let{slug:t,environment:a,secretName:r,description:n,excludeCharacters:i,excludeLowercase:s,excludeNumbers:o,excludePunctuation:c,excludeUppercase:l,passwordLength:u,requireEachIncludedType:m,kmsKeyId:p,tags:g}=e,h=r||A({slug:t,environment:a,resourceType:"secret"}),y=f(h),b={Type:"AWS::SecretsManager::Secret",Properties:{Name:h,Description:n,GenerateSecretString:{ExcludeCharacters:i,ExcludeLowercase:s,ExcludeNumbers:o,ExcludePunctuation:c,ExcludeUppercase:l,PasswordLength:u||32,RequireEachIncludedType:m!==!1},Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:a},...g?Object.entries(g).map(([T,w])=>({Key:T,Value:w})):[]]}};if(p)b.Properties.KmsKeyId=p;return{secret:b,logicalId:y}}static createDatabaseSecret(e){let{slug:t,environment:a,secretName:r,username:n,dbname:i,engine:s,host:o,port:c,kmsKeyId:l}=e,u=r||A({slug:t,environment:a,resourceType:"db-secret"}),m=f(u),p={username:n};if(i)p.dbname=i;if(s)p.engine=s;if(o)p.host=o;if(c)p.port=c;let g={Type:"AWS::SecretsManager::Secret",Properties:{Name:u,Description:`Database credentials for ${n}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(p),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:a},{Key:"Type",Value:"database"}]}};if(l)g.Properties.KmsKeyId=l;return{secret:g,logicalId:m}}static attachToDatabase(e){let{slug:t,environment:a,secretId:r,targetId:n,targetType:i}=e,s=A({slug:t,environment:a,resourceType:"secret-attachment"}),o=f(s);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:r,TargetId:n,TargetType:i}},logicalId:o}}static enableRotation(e){let{slug:t,environment:a,secretId:r,rotationLambdaArn:n,automaticallyAfterDays:i,rotationType:s,kmsKeyArn:o,vpcSecurityGroupIds:c,vpcSubnetIds:l}=e,u=A({slug:t,environment:a,resourceType:"secret-rotation"}),m=f(u),p={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:r,RotationRules:{AutomaticallyAfterDays:i||30}}};if(n)p.Properties.RotationLambdaARN=n;else if(s)p.Properties.HostedRotationLambda={RotationType:s,KmsKeyArn:o,VpcSecurityGroupIds:c,VpcSubnetIds:l};return{rotation:p,logicalId:m}}static SecretTypes={apiKey:(e,t,a)=>ze.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-${a}-api-key`,description:`API key for ${a}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,t,a)=>ze.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-${a}-oauth-secret`,description:`OAuth client secret for ${a}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,t)=>ze.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,t)=>ze.createGeneratedSecret({slug:e,environment:t,secretName:`${e}-${t}-encryption-key`,description:"Data encryption key",passwordLength:64,excludeCharacters:"+/=",excludePunctuation:!0})};static RotationTypes={MySQLSingleUser:"MySQLSingleUser",MySQLMultiUser:"MySQLMultiUser",PostgreSQLSingleUser:"PostgreSQLSingleUser",PostgreSQLMultiUser:"PostgreSQLMultiUser",OracleSingleUser:"OracleSingleUser",OracleMultiUser:"OracleMultiUser",MariaDBSingleUser:"MariaDBSingleUser",MariaDBMultiUser:"MariaDBMultiUser",SQLServerSingleUser:"SQLServerSingleUser",SQLServerMultiUser:"SQLServerMultiUser",RedshiftSingleUser:"RedshiftSingleUser",RedshiftMultiUser:"RedshiftMultiUser",MongoDBSingleUser:"MongoDBSingleUser",MongoDBMultiUser:"MongoDBMultiUser"}}class W{static createParameter(e){let{slug:t,environment:a,parameterName:r,value:n,type:i="String",description:s,tier:o="Standard",tags:c}=e,l=r||A({slug:t,environment:a,resourceType:"parameter"}),u=f(l);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${t}/${a}/${l}`,Type:i,Value:n,Description:s,Tier:o,Tags:{Name:l,Environment:a,...c}}},logicalId:u}}static createString(e,t,a,r,n){return W.createParameter({slug:e,environment:t,parameterName:a,value:r,type:"String",description:n})}static createSecureString(e,t,a,r,n){return W.createParameter({slug:e,environment:t,parameterName:a,value:r,type:"SecureString",description:n})}static createStringList(e,t,a,r,n){return W.createParameter({slug:e,environment:t,parameterName:a,value:r.join(","),type:"StringList",description:n})}static Parameters={databaseUrl:(e,t,a)=>W.createSecureString(e,t,"database-url",a,"Database connection URL"),apiEndpoint:(e,t,a)=>W.createString(e,t,"api-endpoint",a,"API endpoint URL"),appVersion:(e,t,a)=>W.createString(e,t,"app-version",a,"Application version"),featureFlags:(e,t,a)=>W.createStringList(e,t,"feature-flags",a,"Enabled feature flags"),apiKey:(e,t,a,r)=>W.createSecureString(e,t,`${a}-api-key`,r,`API key for ${a}`),oauthCredentials:(e,t,a,r)=>{let n=W.createString(e,t,"oauth-client-id",a,"OAuth client ID"),i=W.createSecureString(e,t,"oauth-client-secret",r,"OAuth client secret");return{clientId:n,clientSecret:i}},smtpCredentials:(e,t,a,r,n,i)=>{let s=W.createString(e,t,"smtp-username",a,"SMTP username"),o=W.createSecureString(e,t,"smtp-password",r,"SMTP password"),c=W.createString(e,t,"smtp-host",n,"SMTP host"),l=W.createString(e,t,"smtp-port",i.toString(),"SMTP port");return{username:s,password:o,host:c,port:l}},redisUrl:(e,t,a)=>W.createSecureString(e,t,"redis-url",a,"Redis connection URL"),s3Bucket:(e,t,a)=>W.createString(e,t,"s3-bucket",a,"S3 bucket name"),cloudFrontDistribution:(e,t,a)=>W.createString(e,t,"cloudfront-distribution-id",a,"CloudFront distribution ID")}}class Qe{static createDomain(e){let{slug:t,environment:a,domainName:r,engineVersion:n="OpenSearch_2.11",instanceType:i="t3.small.search",instanceCount:s=1,volumeSize:o=10,volumeType:c="gp3",dedicatedMaster:l=!1,dedicatedMasterType:u,dedicatedMasterCount:m=3,multiAz:p=!1,availabilityZoneCount:g=2,vpc:h,encryption:y,enforceHttps:b=!0,tlsSecurityPolicy:T="Policy-Min-TLS-1-2-2019-07",advancedSecurity:w,autoSnapshotHour:S=0,autoTune:E=!0,tags:v={}}=e,P=r||A({slug:t,environment:a,resourceType:"search"}),N=f(P);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:P,EngineVersion:n,ClusterConfig:{InstanceType:i,InstanceCount:s,DedicatedMasterEnabled:l,...l&&{DedicatedMasterType:u||i,DedicatedMasterCount:m},ZoneAwarenessEnabled:p,...p&&{ZoneAwarenessConfig:{AvailabilityZoneCount:g}}},EBSOptions:{EBSEnabled:!0,VolumeType:c,VolumeSize:o},DomainEndpointOptions:{EnforceHTTPS:b,TLSSecurityPolicy:T},SnapshotOptions:{AutomatedSnapshotStartHour:S},...h&&{VPCOptions:{SubnetIds:h.subnetIds,SecurityGroupIds:h.securityGroupIds}},...y&&{EncryptionAtRestOptions:{Enabled:y.atRest??!0,...y.kmsKeyId&&{KmsKeyId:y.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:y.nodeToNode??!0}},...w&&{AdvancedSecurityOptions:{Enabled:w.enabled,InternalUserDatabaseEnabled:w.internalUserDatabase??!0,...w.masterUserName&&w.masterUserPassword&&{MasterUserOptions:{MasterUserName:w.masterUserName,MasterUserPassword:w.masterUserPassword}},...w.masterUserArn&&{MasterUserOptions:{MasterUserARN:w.masterUserArn}}}},...E&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:a},...Object.entries(v).map(([I,D])=>({Key:I,Value:D}))]}},logicalId:N}}static createAccessPolicy(e,t){let{ipAddresses:a,iamPrincipalArns:r,allowAll:n,vpcEndpoint:i}=t;if(n)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let s=[];if(r&&r.length>0)s.push({Effect:"Allow",Principal:{AWS:r},Action:"es:*",Resource:e});if(a&&a.length>0)s.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e,Condition:{IpAddress:{"aws:SourceIp":a}}});if(i)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};return{Version:"2012-10-17",Statement:s}}static DomainPresets={development:(e,t)=>Qe.createDomain({slug:e,environment:t,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,t,a)=>Qe.createDomain({slug:e,environment:t,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:a,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(e,t)=>Qe.createDomain({slug:e,environment:t,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,t,a)=>Qe.createDomain({slug:e,environment:t,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:a,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 mt{static createDomainRedirectBucket(e){let{slug:t,environment:a,sourceDomain:r,targetDomain:n,protocol:i="https"}=e,s=A({slug:t,environment:a,resourceType:"s3",suffix:"redirect"}),o=f(s),c=f(`${s}-policy`),l={Type:"AWS::S3::Bucket",Properties:{BucketName:r,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:n,Protocol:i}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:a},{Key:"Purpose",Value:"Domain Redirect"}]}},u={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:C.Ref(o),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[C.Join("",[C.GetAtt(o,"Arn"),"/*"])]}]}}};return{bucket:l,bucketPolicy:u,logicalId:o,policyLogicalId:c}}static createPathRedirectFunction(e){let{slug:t,environment:a,rules:r}=e,n=A({slug:t,environment:a,resourceType:"cf-redirect"}),i=f(n),s=mt.generateRedirectFunctionCode(r);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:n,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${t} (${a})`,Runtime:"cloudfront-js-2.0"},FunctionCode:s}},logicalId:i,functionCode:s}}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((t)=>{let a=t.preserveQueryString!==!1,r=t.statusCode||301;return` '${t
|
|
|
2367
2367
|
}
|
|
2368
2368
|
|
|
2369
2369
|
return request;
|
|
2370
|
-
}`}static CommonRedirects={wwwToApex:(e,t="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${e}`,targetDomain:e,protocol:t,preservePath:!0}),apexToWww:(e,t="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:e,targetDomain:`www.${e}`,protocol:t,preservePath:!0}),httpToHttps:(e="/")=>({source:e,target:e,statusCode:301}),addTrailingSlash:(e)=>e.map((t)=>({source:t.endsWith("/")?t.slice(0,-1):t,target:t.endsWith("/")?t:`${t}/`,statusCode:301})),removeTrailingSlash:(e)=>e.map((t)=>({source:t.endsWith("/")&&t!=="/"?t:`${t}/`,target:t.endsWith("/")&&t!=="/"?t.slice(0,-1):t,statusCode:301}))};static Patterns={flattenBlogUrls:(e)=>e.map(({oldPath:t,newPath:a})=>({source:t,target:a,statusCode:301,preserveQueryString:!0})),categoryRename:(e,t)=>[{source:`/${e}`,target:`/${t}`,statusCode:301},{source:`/${e}/`,target:`/${t}/`,statusCode:301}],productSlugChange:(e)=>e.map(({oldSlug:t,newSlug:a})=>({source:`/products/${t}`,target:`/products/${a}`,statusCode:301})),apiVersionRedirect:(e,t,a)=>a.map((r)=>({source:`/api/${e}/${r}`,target:`/api/${t}/${r}`,statusCode:307,preserveQueryString:!0})),gonePages:(e)=>e.map((t)=>({source:t,target:"/410",statusCode:301}))};static createRedirectSetup(e){let{slug:t,environment:a,domainRedirects:r=[],pathRedirects:n=[]}=e,i={},s=[];for(let c of r){let{bucket:l,bucketPolicy:u,logicalId:m,policyLogicalId:p}=dt.createDomainRedirectBucket({...c,slug:t,environment:a});i[m]=l,i[p]=u,s.push(m)}let o=null;if(n.length>0){let{function:c,logicalId:l}=dt.createPathRedirectFunction({slug:t,environment:a,rules:n});i[l]=c,o=l}return{resources:i,outputs:{domainRedirectBuckets:s,pathRedirectFunctionLogicalId:o}}}static fromMapping(e,t){return Object.entries(e).map(([a,r])=>({source:a,target:r,statusCode:t?.statusCode||301,preserveQueryString:t?.preserveQueryString??!0}))}static validateRules(e){let t=[],a=[],r=new Set;for(let n of e){if(r.has(n.source))t.push(`Duplicate source path: ${n.source}`);if(r.add(n.source),n.source===n.target)t.push(`Redirect loop detected: ${n.source} -> ${n.target}`);if(!n.target.startsWith("/")&&!n.target.startsWith("http"))a.push(`Target URL should start with / or http: ${n.target}`);if(!n.source||n.source.trim()==="")t.push("Source path cannot be empty");if(!n.target||n.target.trim()==="")t.push("Target path cannot be empty")}for(let n of e){let i=e.find((s)=>s.source===n.target);if(i)a.push(`Potential redirect chain: ${n.source} -> ${n.target} -> ${i.target}`)}return{valid:t.length===0,errors:t,warnings:a}}}class ${static generate(e){let t={},{slug:a,environment:r,region:n="us-east-1"}=e,i=$.createLambdaExecutionRole(a,r);if(Object.assign(t,i.resources),e.email?.enabled){let s=$.generateEmailResources(e,i.roleArn);Object.assign(t,s)}if(e.phone?.enabled){let s=$.generatePhoneResources(e,i.roleArn);Object.assign(t,s)}if(e.sms?.enabled){let s=$.generateSmsResources(e,i.roleArn);Object.assign(t,s)}return t}static createLambdaExecutionRole(e,t){let a=`${e}-${t}-communication-role`,r=f(a);return{resources:{[r]:{Type:"AWS::IAM::Role",Properties:{RoleName:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"CommunicationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish","sns:Subscribe"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchWriteItem","dynamodb:BatchGetItem"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"},{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetEndpoint","mobiletargeting:UpdateEndpoint"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["bedrock:InvokeModel"],Resource:"*"},{Effect:"Allow",Action:["es:ESHttpGet","es:ESHttpPost","es:ESHttpPut","es:ESHttpDelete"],Resource:"*"}]}}]}}},roleArn:C.GetAtt(r,"Arn"),roleName:a}}static generateEmailResources(e,t){let{slug:a,environment:r,email:n}=e;if(!n)return{};let i={},s=`${a}-${r}`,o=`${s}-email-storage`,c=f(o);i[c]={Type:"AWS::S3::Bucket",Properties:{BucketName:o,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:n.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:n.server.storage.archiveAfterDays}]:[],ExpirationInDays:n.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let l=f(`${s}-ses-identity`);if(i[l]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:n.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},n.notifications?.bounces||n.notifications?.complaints){let u=f(`${s}-bounce-topic`);i[u]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${s}-email-bounces`}};let m=f(`${s}-complaint-topic`);i[m]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${s}-email-complaints`}}}if(n.server?.enabled){let u=f(`${s}-inbound-email`);i[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:60,MemorySize:256,Code:{ZipFile:$.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:o,DOMAIN:n.domain}}}};let m=f(`${s}-outbound-email`);i[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:$.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:o,DOMAIN:n.domain}}}}}if(n.advanced?.analytics){let u=f(`${s}-email-analytics`);i[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(n.advanced?.scheduling){let u=f(`${s}-email-scheduler`);i[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:300,MemorySize:256,Code:{ZipFile:$.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:o}}}};let m=f(`${s}-email-scheduler-rule`);i[m]={Type:"AWS::Events::Rule",Properties:{Name:`${s}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:C.GetAtt(u,"Arn")}]}}}if(n.advanced?.threading){let u=f(`${s}-email-threading`);i[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:60,MemorySize:256,Code:{ZipFile:$.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:o}}}}}if(n.advanced?.rules){let u=f(`${s}-email-rules`);i[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-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(n.advanced?.sharedMailboxes){let u=f(`${s}-shared-mailboxes`);i[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-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(n.advanced?.search){let u=f(`${s}-email-search`);i[u]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${s}-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 i}static generatePhoneResources(e,t){let{slug:a,environment:r,phone:n}=e;if(!n)return{};let i={},s=`${a}-${r}`,o=f(`${s}-call-log`);if(i[o]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},n.voicemail?.enabled){let u=f(`${s}-voicemail`);i[u]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${s}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let c=f(`${s}-phone-notifications`);i[c]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${s}-phone-notifications`}};let l=f(`${s}-incoming-call`);if(i[l]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:$.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${s}-call-log`,NOTIFICATION_TOPIC_ARN:C.Ref(c)}}}},n.voicemail?.enabled){let u=f(`${s}-voicemail-handler`);i[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:n.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:$.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${s}-voicemail`,TRANSCRIPTION_ENABLED:String(n.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:C.Ref(c)}}}}}if(n.advanced?.recording){let u=f(`${s}-call-recordings`);i[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(n.advanced?.callbacks){let u=f(`${s}-callbacks`);i[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(n.advanced?.analytics){let u=f(`${s}-call-metrics`);i[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return i}static generateSmsResources(e,t){let{slug:a,environment:r,sms:n}=e;if(!n)return{};let i={},s=`${a}-${r}`,o=f(`${s}-pinpoint-app`);i[o]={Type:"AWS::Pinpoint::App",Properties:{Name:`${s}-sms`}};let c=f(`${s}-sms-channel`);i[c]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:C.Ref(o),Enabled:!0,SenderId:n.senderId}};let l=f(`${s}-sms-log`);if(i[l]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-sms-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},n.optOut?.enabled){let g=f(`${s}-sms-optout`);i[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let u=f(`${s}-sms-notifications`);i[u]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${s}-sms-notifications`}};let m=f(`${s}-send-sms`);i[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:$.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:C.Ref(o),MESSAGE_LOG_TABLE:`${s}-sms-log`,OPT_OUT_TABLE:n.optOut?.enabled?`${s}-sms-optout`:"",MESSAGE_TYPE:n.messageType||"TRANSACTIONAL"}}}};let p=f(`${s}-receive-sms`);if(i[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:$.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${s}-sms-log`,OPT_OUT_TABLE:n.optOut?.enabled?`${s}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:C.Ref(u)}}}},n.advanced?.campaigns){let g=f(`${s}-sms-campaigns`);i[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(n.advanced?.analytics){let g=f(`${s}-sms-analytics`);i[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(n.advanced?.linkTracking){let g=f(`${s}-short-links`);i[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(n.advanced?.chatbot){let g=f(`${s}-chatbot-sessions`);i[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let h=f(`${s}-chatbot-rules`);i[h]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(n.advanced?.abTesting){let g=f(`${s}-ab-tests`);i[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(n.advanced?.mms){let g=f(`${s}-mms-media`);i[g]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${s}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return i}static InboundEmailCode=`
|
|
2370
|
+
}`}static CommonRedirects={wwwToApex:(e,t="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${e}`,targetDomain:e,protocol:t,preservePath:!0}),apexToWww:(e,t="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:e,targetDomain:`www.${e}`,protocol:t,preservePath:!0}),httpToHttps:(e="/")=>({source:e,target:e,statusCode:301}),addTrailingSlash:(e)=>e.map((t)=>({source:t.endsWith("/")?t.slice(0,-1):t,target:t.endsWith("/")?t:`${t}/`,statusCode:301})),removeTrailingSlash:(e)=>e.map((t)=>({source:t.endsWith("/")&&t!=="/"?t:`${t}/`,target:t.endsWith("/")&&t!=="/"?t.slice(0,-1):t,statusCode:301}))};static Patterns={flattenBlogUrls:(e)=>e.map(({oldPath:t,newPath:a})=>({source:t,target:a,statusCode:301,preserveQueryString:!0})),categoryRename:(e,t)=>[{source:`/${e}`,target:`/${t}`,statusCode:301},{source:`/${e}/`,target:`/${t}/`,statusCode:301}],productSlugChange:(e)=>e.map(({oldSlug:t,newSlug:a})=>({source:`/products/${t}`,target:`/products/${a}`,statusCode:301})),apiVersionRedirect:(e,t,a)=>a.map((r)=>({source:`/api/${e}/${r}`,target:`/api/${t}/${r}`,statusCode:307,preserveQueryString:!0})),gonePages:(e)=>e.map((t)=>({source:t,target:"/410",statusCode:301}))};static createRedirectSetup(e){let{slug:t,environment:a,domainRedirects:r=[],pathRedirects:n=[]}=e,i={},s=[];for(let c of r){let{bucket:l,bucketPolicy:u,logicalId:m,policyLogicalId:p}=mt.createDomainRedirectBucket({...c,slug:t,environment:a});i[m]=l,i[p]=u,s.push(m)}let o=null;if(n.length>0){let{function:c,logicalId:l}=mt.createPathRedirectFunction({slug:t,environment:a,rules:n});i[l]=c,o=l}return{resources:i,outputs:{domainRedirectBuckets:s,pathRedirectFunctionLogicalId:o}}}static fromMapping(e,t){return Object.entries(e).map(([a,r])=>({source:a,target:r,statusCode:t?.statusCode||301,preserveQueryString:t?.preserveQueryString??!0}))}static validateRules(e){let t=[],a=[],r=new Set;for(let n of e){if(r.has(n.source))t.push(`Duplicate source path: ${n.source}`);if(r.add(n.source),n.source===n.target)t.push(`Redirect loop detected: ${n.source} -> ${n.target}`);if(!n.target.startsWith("/")&&!n.target.startsWith("http"))a.push(`Target URL should start with / or http: ${n.target}`);if(!n.source||n.source.trim()==="")t.push("Source path cannot be empty");if(!n.target||n.target.trim()==="")t.push("Target path cannot be empty")}for(let n of e){let i=e.find((s)=>s.source===n.target);if(i)a.push(`Potential redirect chain: ${n.source} -> ${n.target} -> ${i.target}`)}return{valid:t.length===0,errors:t,warnings:a}}}class Y{static generate(e){let t={},{slug:a,environment:r,region:n="us-east-1"}=e,i=Y.createLambdaExecutionRole(a,r);if(Object.assign(t,i.resources),e.email?.enabled){let s=Y.generateEmailResources(e,i.roleArn);Object.assign(t,s)}if(e.phone?.enabled){let s=Y.generatePhoneResources(e,i.roleArn);Object.assign(t,s)}if(e.sms?.enabled){let s=Y.generateSmsResources(e,i.roleArn);Object.assign(t,s)}return t}static createLambdaExecutionRole(e,t){let a=`${e}-${t}-communication-role`,r=f(a);return{resources:{[r]:{Type:"AWS::IAM::Role",Properties:{RoleName:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"CommunicationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish","sns:Subscribe"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchWriteItem","dynamodb:BatchGetItem"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"},{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetEndpoint","mobiletargeting:UpdateEndpoint"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["bedrock:InvokeModel"],Resource:"*"},{Effect:"Allow",Action:["es:ESHttpGet","es:ESHttpPost","es:ESHttpPut","es:ESHttpDelete"],Resource:"*"}]}}]}}},roleArn:C.GetAtt(r,"Arn"),roleName:a}}static generateEmailResources(e,t){let{slug:a,environment:r,email:n}=e;if(!n)return{};let i={},s=`${a}-${r}`,o=`${s}-email-storage`,c=f(o);i[c]={Type:"AWS::S3::Bucket",Properties:{BucketName:o,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:n.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:n.server.storage.archiveAfterDays}]:[],ExpirationInDays:n.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let l=f(`${s}-ses-identity`);if(i[l]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:n.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},n.notifications?.bounces||n.notifications?.complaints){let u=f(`${s}-bounce-topic`);i[u]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${s}-email-bounces`}};let m=f(`${s}-complaint-topic`);i[m]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${s}-email-complaints`}}}if(n.server?.enabled){let u=f(`${s}-inbound-email`);i[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:60,MemorySize:256,Code:{ZipFile:Y.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:o,DOMAIN:n.domain}}}};let m=f(`${s}-outbound-email`);i[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:Y.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:o,DOMAIN:n.domain}}}}}if(n.advanced?.analytics){let u=f(`${s}-email-analytics`);i[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(n.advanced?.scheduling){let u=f(`${s}-email-scheduler`);i[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:300,MemorySize:256,Code:{ZipFile:Y.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:o}}}};let m=f(`${s}-email-scheduler-rule`);i[m]={Type:"AWS::Events::Rule",Properties:{Name:`${s}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:C.GetAtt(u,"Arn")}]}}}if(n.advanced?.threading){let u=f(`${s}-email-threading`);i[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:60,MemorySize:256,Code:{ZipFile:Y.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:o}}}}}if(n.advanced?.rules){let u=f(`${s}-email-rules`);i[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-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(n.advanced?.sharedMailboxes){let u=f(`${s}-shared-mailboxes`);i[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-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(n.advanced?.search){let u=f(`${s}-email-search`);i[u]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${s}-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 i}static generatePhoneResources(e,t){let{slug:a,environment:r,phone:n}=e;if(!n)return{};let i={},s=`${a}-${r}`,o=f(`${s}-call-log`);if(i[o]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},n.voicemail?.enabled){let u=f(`${s}-voicemail`);i[u]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${s}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let c=f(`${s}-phone-notifications`);i[c]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${s}-phone-notifications`}};let l=f(`${s}-incoming-call`);if(i[l]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:Y.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${s}-call-log`,NOTIFICATION_TOPIC_ARN:C.Ref(c)}}}},n.voicemail?.enabled){let u=f(`${s}-voicemail-handler`);i[u]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:n.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:Y.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${s}-voicemail`,TRANSCRIPTION_ENABLED:String(n.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:C.Ref(c)}}}}}if(n.advanced?.recording){let u=f(`${s}-call-recordings`);i[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(n.advanced?.callbacks){let u=f(`${s}-callbacks`);i[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(n.advanced?.analytics){let u=f(`${s}-call-metrics`);i[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return i}static generateSmsResources(e,t){let{slug:a,environment:r,sms:n}=e;if(!n)return{};let i={},s=`${a}-${r}`,o=f(`${s}-pinpoint-app`);i[o]={Type:"AWS::Pinpoint::App",Properties:{Name:`${s}-sms`}};let c=f(`${s}-sms-channel`);i[c]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:C.Ref(o),Enabled:!0,SenderId:n.senderId}};let l=f(`${s}-sms-log`);if(i[l]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-sms-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},n.optOut?.enabled){let g=f(`${s}-sms-optout`);i[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let u=f(`${s}-sms-notifications`);i[u]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${s}-sms-notifications`}};let m=f(`${s}-send-sms`);i[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:Y.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:C.Ref(o),MESSAGE_LOG_TABLE:`${s}-sms-log`,OPT_OUT_TABLE:n.optOut?.enabled?`${s}-sms-optout`:"",MESSAGE_TYPE:n.messageType||"TRANSACTIONAL"}}}};let p=f(`${s}-receive-sms`);if(i[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${s}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:t,Timeout:30,MemorySize:256,Code:{ZipFile:Y.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${s}-sms-log`,OPT_OUT_TABLE:n.optOut?.enabled?`${s}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:C.Ref(u)}}}},n.advanced?.campaigns){let g=f(`${s}-sms-campaigns`);i[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(n.advanced?.analytics){let g=f(`${s}-sms-analytics`);i[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(n.advanced?.linkTracking){let g=f(`${s}-short-links`);i[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(n.advanced?.chatbot){let g=f(`${s}-chatbot-sessions`);i[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let h=f(`${s}-chatbot-rules`);i[h]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(n.advanced?.abTesting){let g=f(`${s}-ab-tests`);i[g]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(n.advanced?.mms){let g=f(`${s}-mms-media`);i[g]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${s}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return i}static InboundEmailCode=`
|
|
2371
2371
|
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
2372
2372
|
const s3 = new S3Client({});
|
|
2373
2373
|
exports.handler = async (event) => {
|
|
@@ -2465,7 +2465,7 @@ exports.handler = async (event) => {
|
|
|
2465
2465
|
console.log('Receive SMS:', JSON.stringify(event, null, 2));
|
|
2466
2466
|
// Process inbound SMS, handle opt-out keywords
|
|
2467
2467
|
return { statusCode: 200 };
|
|
2468
|
-
};`}var d={ref:(e)=>({Ref:e}),getAtt:(e,t)=>({"Fn::GetAtt":[e,t]}),join:(e,t)=>({"Fn::Join":[e,t]}),sub:(e,t)=>t?{"Fn::Sub":[e,t]}:{"Fn::Sub":e},select:(e,t)=>({"Fn::Select":[e,t]}),split:(e,t)=>({"Fn::Split":[e,t]}),getAZs:(e="")=>({"Fn::GetAZs":e}),importValue:(e)=>({"Fn::ImportValue":e}),findInMap:(e,t,a)=>({"Fn::FindInMap":[e,t,a]}),base64:(e)=>({"Fn::Base64":e}),cidr:(e,t,a)=>({"Fn::Cidr":[e,t,a]}),equals:(e,t)=>({"Fn::Equals":[e,t]}),if:(e,t,a)=>({"Fn::If":[e,t,a]}),not:(e)=>({"Fn::Not":[e]}),and:(...e)=>({"Fn::And":e}),or:(...e)=>({"Fn::Or":e})},St={s3Bucket:(e)=>d.sub(`arn:aws:s3:::${e}`),s3Object:(e,t="*")=>d.sub(`arn:aws:s3:::${e}/${t}`),lambda:(e,t,a)=>d.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${e}`,t&&a?{"AWS::Region":t,"AWS::AccountId":a}:void 0),dynamodb:(e)=>d.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${e}`),sqs:(e)=>d.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${e}`),sns:(e)=>d.sub(`arn:aws:sns:\${AWS::Region}:\${AWS::AccountId}:${e}`),kinesis:(e)=>d.sub(`arn:aws:kinesis:\${AWS::Region}:\${AWS::AccountId}:stream/${e}`),iam:(e,t)=>d.sub(`arn:aws:iam::\${AWS::AccountId}:${e}/${t}`),secretsManager:(e)=>d.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${e}`),cloudwatch:(e)=>d.sub(`arn:aws:logs:\${AWS::Region}:\${AWS::AccountId}:log-group:${e}`)},wl={ACCOUNT_ID:{Ref:"AWS::AccountId"},NOTIFICATION_ARNS:{Ref:"AWS::NotificationARNs"},NO_VALUE:{Ref:"AWS::NoValue"},PARTITION:{Ref:"AWS::Partition"},REGION:{Ref:"AWS::Region"},STACK_ID:{Ref:"AWS::StackId"},STACK_NAME:{Ref:"AWS::StackName"},URL_SUFFIX:{Ref:"AWS::URLSuffix"}};function ki(e,t){if(t.type==="http")Mi(e,t);else if(t.type==="rest")Li(e,t);else if(t.type==="websocket")xi(e,t)}function Mi(e,t){let a={Name:d.sub("${AWS::StackName}-http-api"),ProtocolType:"HTTP"};if(t.cors)a.CorsConfiguration={AllowOrigins:t.cors.allowOrigins,AllowMethods:t.cors.allowMethods,AllowHeaders:t.cors.allowHeaders||["*"],MaxAge:t.cors.maxAge||300};if(e.addResource("HttpApi","AWS::ApiGatewayV2::Api",a),e.addResource("HttpApiStage","AWS::ApiGatewayV2::Stage",{ApiId:d.ref("HttpApi"),StageName:"$default",AutoDeploy:!0,DefaultRouteSettings:t.throttling?{ThrottlingBurstLimit:t.throttling.burstLimit,ThrottlingRateLimit:t.throttling.rateLimit}:void 0,AccessLogSettings:{DestinationArn:d.getAtt("ApiLogGroup","Arn"),Format:"$context.requestId $context.error.message $context.error.messageString"}},{dependsOn:["HttpApi","ApiLogGroup"]}),e.addResource("ApiLogGroup","AWS::Logs::LogGroup",{LogGroupName:d.sub("/aws/apigateway/${AWS::StackName}-http-api"),RetentionInDays:14}),t.authorizer)Oi(e,"HttpApi",t.authorizer);if(t.customDomain)Ht(e,"HttpApi",t.customDomain,"HTTP");e.addOutputs({HttpApiId:{Description:"HTTP API ID",Value:d.ref("HttpApi"),Export:{Name:d.sub("${AWS::StackName}-http-api-id")}},HttpApiEndpoint:{Description:"HTTP API endpoint",Value:d.getAtt("HttpApi","ApiEndpoint"),Export:{Name:d.sub("${AWS::StackName}-http-api-endpoint")}}})}function Li(e,t){e.addResource("RestApi","AWS::ApiGateway::RestApi",{Name:d.sub("${AWS::StackName}-rest-api"),Description:d.sub("REST API for ${AWS::StackName}"),EndpointConfiguration:{Types:["REGIONAL"]}}),e.addResource("ApiGatewayAccount","AWS::ApiGateway::Account",{CloudWatchRoleArn:d.getAtt("ApiGatewayCloudWatchRole","Arn")},{dependsOn:"ApiGatewayCloudWatchRole"}),e.addResource("ApiGatewayCloudWatchRole","AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"apigateway.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"]}),e.addResource("RestApiDeployment","AWS::ApiGateway::Deployment",{RestApiId:d.ref("RestApi"),Description:"Initial deployment"},{dependsOn:"RestApi"});let a={RestApiId:d.ref("RestApi"),DeploymentId:d.ref("RestApiDeployment"),StageName:"prod",Description:"Production stage",MethodSettings:[{ResourcePath:"/*",HttpMethod:"*",LoggingLevel:"INFO",DataTraceEnabled:!0,MetricsEnabled:!0}]};if(t.throttling)a.MethodSettings[0].ThrottlingBurstLimit=t.throttling.burstLimit,a.MethodSettings[0].ThrottlingRateLimit=t.throttling.rateLimit;if(e.addResource("RestApiStage","AWS::ApiGateway::Stage",a,{dependsOn:["RestApi","RestApiDeployment"]}),t.customDomain)Ht(e,"RestApi",t.customDomain,"REST");e.addOutputs({RestApiId:{Description:"REST API ID",Value:d.ref("RestApi"),Export:{Name:d.sub("${AWS::StackName}-rest-api-id")}},RestApiEndpoint:{Description:"REST API endpoint",Value:d.sub("https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/prod"),Export:{Name:d.sub("${AWS::StackName}-rest-api-endpoint")}}})}function xi(e,t){if(e.addResource("WebSocketApi","AWS::ApiGatewayV2::Api",{Name:d.sub("${AWS::StackName}-websocket-api"),ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action"}),t.routes){if(t.routes.connect)ot(e,"$connect",t.routes.connect.functionName);if(t.routes.disconnect)ot(e,"$disconnect",t.routes.disconnect.functionName);if(t.routes.default)ot(e,"$default",t.routes.default.functionName);if(t.routes.custom)t.routes.custom.forEach((a)=>{ot(e,a.routeKey,a.functionName)})}if(e.addResource("WebSocketApiStage","AWS::ApiGatewayV2::Stage",{ApiId:d.ref("WebSocketApi"),StageName:"prod",AutoDeploy:!0,DefaultRouteSettings:t.throttling?{ThrottlingBurstLimit:t.throttling.burstLimit,ThrottlingRateLimit:t.throttling.rateLimit}:void 0},{dependsOn:"WebSocketApi"}),t.customDomain)Ht(e,"WebSocketApi",t.customDomain,"WEBSOCKET");e.addOutputs({WebSocketApiId:{Description:"WebSocket API ID",Value:d.ref("WebSocketApi"),Export:{Name:d.sub("${AWS::StackName}-websocket-api-id")}},WebSocketApiEndpoint:{Description:"WebSocket API endpoint",Value:d.getAtt("WebSocketApi","ApiEndpoint"),Export:{Name:d.sub("${AWS::StackName}-websocket-api-endpoint")}}})}function ot(e,t,a){let r=e.toLogicalId(`websocket-route-${t}`),n=e.toLogicalId(`websocket-integration-${t}`),i=e.toLogicalId(`${a}-function`);e.addResource(n,"AWS::ApiGatewayV2::Integration",{ApiId:d.ref("WebSocketApi"),IntegrationType:"AWS_PROXY",IntegrationUri:d.sub(`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${i}.Arn}/invocations`)},{dependsOn:["WebSocketApi",i]}),e.addResource(r,"AWS::ApiGatewayV2::Route",{ApiId:d.ref("WebSocketApi"),RouteKey:t,Target:d.join("/",["integrations",d.ref(n)])},{dependsOn:["WebSocketApi",n]}),e.addResource(`${r}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(i),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:d.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*")},{dependsOn:[i,"WebSocketApi"]})}function Ht(e,t,a,r){let n={DomainName:a.domain};if(r==="REST")n.CertificateArn=a.certificateArn,n.EndpointConfiguration={Types:["REGIONAL"]},e.addResource("ApiCustomDomain","AWS::ApiGateway::DomainName",n),e.addResource("ApiBasePathMapping","AWS::ApiGateway::BasePathMapping",{DomainName:d.ref("ApiCustomDomain"),RestApiId:d.ref(t),Stage:d.ref("RestApiStage")},{dependsOn:["ApiCustomDomain",t,"RestApiStage"]});else n.DomainNameConfigurations=[{CertificateArn:a.certificateArn,EndpointType:"REGIONAL"}],e.addResource("ApiCustomDomain","AWS::ApiGatewayV2::DomainName",n),e.addResource("ApiMapping","AWS::ApiGatewayV2::ApiMapping",{ApiId:d.ref(t),DomainName:d.ref("ApiCustomDomain"),Stage:r==="HTTP"?d.ref("HttpApiStage"):d.ref("WebSocketApiStage")},{dependsOn:["ApiCustomDomain",t]});if(a.dnsProvider!=="external")e.addResource("ApiDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:d.sub(`${Wi(a.domain)}.`),Name:a.domain,Type:"A",AliasTarget:{HostedZoneId:d.getAtt("ApiCustomDomain","RegionalHostedZoneId"),DNSName:d.getAtt("ApiCustomDomain","RegionalDomainName"),EvaluateTargetHealth:!1}},{dependsOn:"ApiCustomDomain"});e.addOutputs({ApiCustomDomainName:{Description:"Configured API custom domain",Value:a.domain},ApiCustomDomainTarget:{Description:"DNS target for Route53 or an external DNS provider",Value:d.getAtt("ApiCustomDomain","RegionalDomainName")},ApiCustomDomainHostedZoneId:{Description:"Regional API Gateway hosted zone ID",Value:d.getAtt("ApiCustomDomain","RegionalHostedZoneId")}})}function Oi(e,t,a){if(!a)return;if(a.type==="jwt")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:d.ref(t),AuthorizerType:"JWT",IdentitySource:[a.identitySource||"$request.header.Authorization"],JwtConfiguration:{Issuer:a.issuer,Audience:a.audience},Name:"JWTAuthorizer"},{dependsOn:t});else if(a.type==="lambda")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:d.ref(t),AuthorizerType:"REQUEST",AuthorizerUri:a.authorizerUri,IdentitySource:[a.identitySource||"$request.header.Authorization"],Name:"LambdaAuthorizer"},{dependsOn:t})}function Wi(e){let t=e.split(".");if(t.length>=2)return t.slice(-2).join(".");return e}function _i(e,t){if(t.redis)Bi(e,t.redis);if(t.memcached)Ui(e,t.memcached);if(t.elasticache)Gi(e,t.elasticache)}function Bi(e,t){if(!t)return;if(e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache Redis cluster",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Redis",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:t.port||6379,ToPort:t.port||6379,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]}),t.parameterGroup&&Object.keys(t.parameterGroup).length>0)e.addResource("CacheParameterGroup","AWS::ElastiCache::ParameterGroup",{Description:"Parameter group for Redis",CacheParameterGroupFamily:`redis${t.engineVersion.split(".")[0]}`,Properties:t.parameterGroup});if(t.numCacheNodes>1||t.automaticFailoverEnabled)e.addResource("RedisReplicationGroup","AWS::ElastiCache::ReplicationGroup",{ReplicationGroupDescription:"Redis replication group",ReplicationGroupId:d.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheClusters:t.numCacheNodes,AutomaticFailoverEnabled:t.automaticFailoverEnabled||!1,MultiAZEnabled:t.automaticFailoverEnabled||!1,Port:t.port||6379,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),SecurityGroupIds:[d.ref("CacheSecurityGroup")],CacheParameterGroupName:t.parameterGroup?d.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:t.snapshotRetentionLimit||5,SnapshotWindow:t.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",AtRestEncryptionEnabled:!0,TransitEncryptionEnabled:!0,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-redis")}]},{dependsOn:t.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis primary endpoint",Value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address"),Export:{Name:d.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port"),Export:{Name:d.sub("${AWS::StackName}-redis-port")}}});else e.addResource("RedisCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:d.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheNodes:1,Port:t.port||6379,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[d.ref("CacheSecurityGroup")],CacheParameterGroupName:t.parameterGroup?d.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:t.snapshotRetentionLimit||5,SnapshotWindow:t.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-redis")}]},{dependsOn:t.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis endpoint",Value:d.getAtt("RedisCacheCluster","RedisEndpoint.Address"),Export:{Name:d.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:d.getAtt("RedisCacheCluster","RedisEndpoint.Port"),Export:{Name:d.sub("${AWS::StackName}-redis-port")}}})}function Ui(e,t){if(!t)return;if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Memcached",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:t.port||11211,ToPort:t.port||11211,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("MemcachedCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:d.sub("${AWS::StackName}-memcached"),Engine:"memcached",EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheNodes:t.numCacheNodes,Port:t.port||11211,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[d.ref("CacheSecurityGroup")],PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-memcached")}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]}),e.addOutputs({MemcachedEndpoint:{Description:"Memcached configuration endpoint",Value:d.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Address"),Export:{Name:d.sub("${AWS::StackName}-memcached-endpoint")}},MemcachedPort:{Description:"Memcached port",Value:d.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Port"),Export:{Name:d.sub("${AWS::StackName}-memcached-port")}}})}function Gi(e,t){if(!t)return;let a=t.engine==="redis";if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:a?6379:11211,ToPort:a?6379:11211,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("CacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:d.sub(`\${AWS::StackName}-${t.engine}`),Engine:t.engine,EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheNodes:t.numCacheNodes,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[d.ref("CacheSecurityGroup")],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.engine}`)}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]})}function Vi(e,t){if(!t.enabled)return;e.addResource("CloudFrontOriginAccessIdentity","AWS::CloudFront::CloudFrontOriginAccessIdentity",{CloudFrontOriginAccessIdentityConfig:{Comment:d.sub("${AWS::StackName} CloudFront OAI")}});let a=[],r=[];if(!t.origins||t.origins.length===0)a.push({Id:"S3Origin",DomainName:d.getAtt("StaticBucket","DomainName"),S3OriginConfig:{OriginAccessIdentity:d.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")}});else t.origins.forEach((s,o)=>{let c={Id:s.id,DomainName:s.domainName};if(s.originPath)c.OriginPath=s.originPath;if(s.domainName.includes("s3"))c.S3OriginConfig={OriginAccessIdentity:d.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")};else c.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"]};if(a.push(c),o>0||s.pathPattern)r.push({PathPattern:s.pathPattern||`/${s.id}/*`,TargetOriginId:s.id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:t.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:t.cachePolicy?.minTTL||0,DefaultTTL:t.cachePolicy?.defaultTTL||86400,MaxTTL:t.cachePolicy?.maxTTL||31536000})});let n={TargetOriginId:a[0].Id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:t.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:t.cachePolicy?.minTTL||0,DefaultTTL:t.cachePolicy?.defaultTTL||86400,MaxTTL:t.cachePolicy?.maxTTL||31536000};if(t.edgeFunctions&&t.edgeFunctions.length>0)n.LambdaFunctionAssociations=t.edgeFunctions.map((s)=>({EventType:s.eventType,LambdaFunctionARN:s.functionArn}));let i={Enabled:!0,HttpVersion:t.http3?"http3":"http2",IPV6Enabled:!0,Origins:a,DefaultCacheBehavior:n,PriceClass:t.priceClass||"PriceClass_100",ViewerCertificate:{}};if(r.length>0)i.CacheBehaviors=r;if(t.customDomain)i.Aliases=[t.customDomain.domain],i.ViewerCertificate={AcmCertificateArn:t.customDomain.certificateArn,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else i.ViewerCertificate={CloudFrontDefaultCertificate:!0};if(t.errorPages)i.CustomErrorResponses=Object.entries(t.errorPages).map(([s,o])=>({ErrorCode:Number.parseInt(s),ResponseCode:200,ResponsePagePath:o,ErrorCachingMinTTL:300}));if(i.DefaultRootObject="index.html",i.Comment=d.sub("${AWS::StackName} CloudFront Distribution"),e.addResource("CloudFrontDistribution","AWS::CloudFront::Distribution",{DistributionConfig:i},{dependsOn:"CloudFrontOriginAccessIdentity"}),!t.origins||t.origins.length===0)e.addResource("StaticBucketPolicyForCloudFront","AWS::S3::BucketPolicy",{Bucket:d.ref("StaticBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontAccess",Effect:"Allow",Principal:{CanonicalUser:d.getAtt("CloudFrontOriginAccessIdentity","S3CanonicalUserId")},Action:"s3:GetObject",Resource:d.join("",[d.getAtt("StaticBucket","Arn"),"/*"])}]}},{dependsOn:["StaticBucket","CloudFrontOriginAccessIdentity"]});if(t.customDomain)e.addResource("CloudFrontDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:d.sub(`${Fi(t.customDomain.domain)}.`),Name:t.customDomain.domain,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:d.getAtt("CloudFrontDistribution","DomainName"),EvaluateTargetHealth:!1}},{dependsOn:"CloudFrontDistribution"});if(e.addOutputs({CloudFrontDistributionId:{Description:"CloudFront distribution ID",Value:d.ref("CloudFrontDistribution"),Export:{Name:d.sub("${AWS::StackName}-cloudfront-id")}},CloudFrontDomainName:{Description:"CloudFront distribution domain name",Value:d.getAtt("CloudFrontDistribution","DomainName"),Export:{Name:d.sub("${AWS::StackName}-cloudfront-domain")}}}),t.customDomain)e.addOutputs({CloudFrontURL:{Description:"CloudFront custom domain URL",Value:d.sub(`https://${t.customDomain.domain}`)}})}function Fi(e){let t=e.split(".");if(t.length>=2)return t.slice(-2).join(".");return e}function ji(e,t){if(t.server)Ki(e,t.server);if(t.fargate)pa(e,"app",t.fargate);if(t.services)t.services.forEach((a)=>{if(a.type==="fargate")pa(e,a.name,{taskDefinition:a.taskDefinition,service:a.service})})}function Ki(e,t){if(!t)return;e.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for application instances",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:3000,ToPort:3000,SourceSecurityGroupId:d.ref("ALBSecurityGroup")},{IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:"0.0.0.0/0"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-app-sg")}]},{dependsOn:"VPC"}),e.addResource("EC2InstanceRole","AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ec2.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore","arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-ec2-role")}]}),e.addResource("EC2InstanceProfile","AWS::IAM::InstanceProfile",{Roles:[d.ref("EC2InstanceRole")]},{dependsOn:"EC2InstanceRole"});let a=t.userData||`#!/bin/bash
|
|
2468
|
+
};`}var d={ref:(e)=>({Ref:e}),getAtt:(e,t)=>({"Fn::GetAtt":[e,t]}),join:(e,t)=>({"Fn::Join":[e,t]}),sub:(e,t)=>t?{"Fn::Sub":[e,t]}:{"Fn::Sub":e},select:(e,t)=>({"Fn::Select":[e,t]}),split:(e,t)=>({"Fn::Split":[e,t]}),getAZs:(e="")=>({"Fn::GetAZs":e}),importValue:(e)=>({"Fn::ImportValue":e}),findInMap:(e,t,a)=>({"Fn::FindInMap":[e,t,a]}),base64:(e)=>({"Fn::Base64":e}),cidr:(e,t,a)=>({"Fn::Cidr":[e,t,a]}),equals:(e,t)=>({"Fn::Equals":[e,t]}),if:(e,t,a)=>({"Fn::If":[e,t,a]}),not:(e)=>({"Fn::Not":[e]}),and:(...e)=>({"Fn::And":e}),or:(...e)=>({"Fn::Or":e})},bt={s3Bucket:(e)=>d.sub(`arn:aws:s3:::${e}`),s3Object:(e,t="*")=>d.sub(`arn:aws:s3:::${e}/${t}`),lambda:(e,t,a)=>d.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${e}`,t&&a?{"AWS::Region":t,"AWS::AccountId":a}:void 0),dynamodb:(e)=>d.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${e}`),sqs:(e)=>d.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${e}`),sns:(e)=>d.sub(`arn:aws:sns:\${AWS::Region}:\${AWS::AccountId}:${e}`),kinesis:(e)=>d.sub(`arn:aws:kinesis:\${AWS::Region}:\${AWS::AccountId}:stream/${e}`),iam:(e,t)=>d.sub(`arn:aws:iam::\${AWS::AccountId}:${e}/${t}`),secretsManager:(e)=>d.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${e}`),cloudwatch:(e)=>d.sub(`arn:aws:logs:\${AWS::Region}:\${AWS::AccountId}:log-group:${e}`)},El={ACCOUNT_ID:{Ref:"AWS::AccountId"},NOTIFICATION_ARNS:{Ref:"AWS::NotificationARNs"},NO_VALUE:{Ref:"AWS::NoValue"},PARTITION:{Ref:"AWS::Partition"},REGION:{Ref:"AWS::Region"},STACK_ID:{Ref:"AWS::StackId"},STACK_NAME:{Ref:"AWS::StackName"},URL_SUFFIX:{Ref:"AWS::URLSuffix"}};function $i(e,t){if(t.type==="http")Li(e,t);else if(t.type==="rest")Mi(e,t);else if(t.type==="websocket")xi(e,t)}function Li(e,t){let a={Name:d.sub("${AWS::StackName}-http-api"),ProtocolType:"HTTP"};if(t.cors)a.CorsConfiguration={AllowOrigins:t.cors.allowOrigins,AllowMethods:t.cors.allowMethods,AllowHeaders:t.cors.allowHeaders||["*"],MaxAge:t.cors.maxAge||300};if(e.addResource("HttpApi","AWS::ApiGatewayV2::Api",a),e.addResource("HttpApiStage","AWS::ApiGatewayV2::Stage",{ApiId:d.ref("HttpApi"),StageName:"$default",AutoDeploy:!0,DefaultRouteSettings:t.throttling?{ThrottlingBurstLimit:t.throttling.burstLimit,ThrottlingRateLimit:t.throttling.rateLimit}:void 0,AccessLogSettings:{DestinationArn:d.getAtt("ApiLogGroup","Arn"),Format:"$context.requestId $context.error.message $context.error.messageString"}},{dependsOn:["HttpApi","ApiLogGroup"]}),e.addResource("ApiLogGroup","AWS::Logs::LogGroup",{LogGroupName:d.sub("/aws/apigateway/${AWS::StackName}-http-api"),RetentionInDays:14}),t.authorizer)Oi(e,"HttpApi",t.authorizer);if(t.customDomain)Ht(e,"HttpApi",t.customDomain,"HTTP");e.addOutputs({HttpApiId:{Description:"HTTP API ID",Value:d.ref("HttpApi"),Export:{Name:d.sub("${AWS::StackName}-http-api-id")}},HttpApiEndpoint:{Description:"HTTP API endpoint",Value:d.getAtt("HttpApi","ApiEndpoint"),Export:{Name:d.sub("${AWS::StackName}-http-api-endpoint")}}})}function Mi(e,t){e.addResource("RestApi","AWS::ApiGateway::RestApi",{Name:d.sub("${AWS::StackName}-rest-api"),Description:d.sub("REST API for ${AWS::StackName}"),EndpointConfiguration:{Types:["REGIONAL"]}}),e.addResource("ApiGatewayAccount","AWS::ApiGateway::Account",{CloudWatchRoleArn:d.getAtt("ApiGatewayCloudWatchRole","Arn")},{dependsOn:"ApiGatewayCloudWatchRole"}),e.addResource("ApiGatewayCloudWatchRole","AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"apigateway.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs"]}),e.addResource("RestApiDeployment","AWS::ApiGateway::Deployment",{RestApiId:d.ref("RestApi"),Description:"Initial deployment"},{dependsOn:"RestApi"});let a={RestApiId:d.ref("RestApi"),DeploymentId:d.ref("RestApiDeployment"),StageName:"prod",Description:"Production stage",MethodSettings:[{ResourcePath:"/*",HttpMethod:"*",LoggingLevel:"INFO",DataTraceEnabled:!0,MetricsEnabled:!0}]};if(t.throttling)a.MethodSettings[0].ThrottlingBurstLimit=t.throttling.burstLimit,a.MethodSettings[0].ThrottlingRateLimit=t.throttling.rateLimit;if(e.addResource("RestApiStage","AWS::ApiGateway::Stage",a,{dependsOn:["RestApi","RestApiDeployment"]}),t.customDomain)Ht(e,"RestApi",t.customDomain,"REST");e.addOutputs({RestApiId:{Description:"REST API ID",Value:d.ref("RestApi"),Export:{Name:d.sub("${AWS::StackName}-rest-api-id")}},RestApiEndpoint:{Description:"REST API endpoint",Value:d.sub("https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/prod"),Export:{Name:d.sub("${AWS::StackName}-rest-api-endpoint")}}})}function xi(e,t){if(e.addResource("WebSocketApi","AWS::ApiGatewayV2::Api",{Name:d.sub("${AWS::StackName}-websocket-api"),ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action"}),t.routes){if(t.routes.connect)ct(e,"$connect",t.routes.connect.functionName);if(t.routes.disconnect)ct(e,"$disconnect",t.routes.disconnect.functionName);if(t.routes.default)ct(e,"$default",t.routes.default.functionName);if(t.routes.custom)t.routes.custom.forEach((a)=>{ct(e,a.routeKey,a.functionName)})}if(e.addResource("WebSocketApiStage","AWS::ApiGatewayV2::Stage",{ApiId:d.ref("WebSocketApi"),StageName:"prod",AutoDeploy:!0,DefaultRouteSettings:t.throttling?{ThrottlingBurstLimit:t.throttling.burstLimit,ThrottlingRateLimit:t.throttling.rateLimit}:void 0},{dependsOn:"WebSocketApi"}),t.customDomain)Ht(e,"WebSocketApi",t.customDomain,"WEBSOCKET");e.addOutputs({WebSocketApiId:{Description:"WebSocket API ID",Value:d.ref("WebSocketApi"),Export:{Name:d.sub("${AWS::StackName}-websocket-api-id")}},WebSocketApiEndpoint:{Description:"WebSocket API endpoint",Value:d.getAtt("WebSocketApi","ApiEndpoint"),Export:{Name:d.sub("${AWS::StackName}-websocket-api-endpoint")}}})}function ct(e,t,a){let r=e.toLogicalId(`websocket-route-${t}`),n=e.toLogicalId(`websocket-integration-${t}`),i=e.toLogicalId(`${a}-function`);e.addResource(n,"AWS::ApiGatewayV2::Integration",{ApiId:d.ref("WebSocketApi"),IntegrationType:"AWS_PROXY",IntegrationUri:d.sub(`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${i}.Arn}/invocations`)},{dependsOn:["WebSocketApi",i]}),e.addResource(r,"AWS::ApiGatewayV2::Route",{ApiId:d.ref("WebSocketApi"),RouteKey:t,Target:d.join("/",["integrations",d.ref(n)])},{dependsOn:["WebSocketApi",n]}),e.addResource(`${r}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(i),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:d.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*")},{dependsOn:[i,"WebSocketApi"]})}function Ht(e,t,a,r){let n={DomainName:a.domain};if(r==="REST")n.CertificateArn=a.certificateArn,n.EndpointConfiguration={Types:["REGIONAL"]},e.addResource("ApiCustomDomain","AWS::ApiGateway::DomainName",n),e.addResource("ApiBasePathMapping","AWS::ApiGateway::BasePathMapping",{DomainName:d.ref("ApiCustomDomain"),RestApiId:d.ref(t),Stage:d.ref("RestApiStage")},{dependsOn:["ApiCustomDomain",t,"RestApiStage"]});else n.DomainNameConfigurations=[{CertificateArn:a.certificateArn,EndpointType:"REGIONAL"}],e.addResource("ApiCustomDomain","AWS::ApiGatewayV2::DomainName",n),e.addResource("ApiMapping","AWS::ApiGatewayV2::ApiMapping",{ApiId:d.ref(t),DomainName:d.ref("ApiCustomDomain"),Stage:r==="HTTP"?d.ref("HttpApiStage"):d.ref("WebSocketApiStage")},{dependsOn:["ApiCustomDomain",t]});if(a.dnsProvider!=="external")e.addResource("ApiDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:d.sub(`${Bi(a.domain)}.`),Name:a.domain,Type:"A",AliasTarget:{HostedZoneId:d.getAtt("ApiCustomDomain","RegionalHostedZoneId"),DNSName:d.getAtt("ApiCustomDomain","RegionalDomainName"),EvaluateTargetHealth:!1}},{dependsOn:"ApiCustomDomain"});e.addOutputs({ApiCustomDomainName:{Description:"Configured API custom domain",Value:a.domain},ApiCustomDomainTarget:{Description:"DNS target for Route53 or an external DNS provider",Value:d.getAtt("ApiCustomDomain","RegionalDomainName")},ApiCustomDomainHostedZoneId:{Description:"Regional API Gateway hosted zone ID",Value:d.getAtt("ApiCustomDomain","RegionalHostedZoneId")}})}function Oi(e,t,a){if(!a)return;if(a.type==="jwt")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:d.ref(t),AuthorizerType:"JWT",IdentitySource:[a.identitySource||"$request.header.Authorization"],JwtConfiguration:{Issuer:a.issuer,Audience:a.audience},Name:"JWTAuthorizer"},{dependsOn:t});else if(a.type==="lambda")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:d.ref(t),AuthorizerType:"REQUEST",AuthorizerUri:a.authorizerUri,IdentitySource:[a.identitySource||"$request.header.Authorization"],Name:"LambdaAuthorizer"},{dependsOn:t})}function Bi(e){let t=e.split(".");if(t.length>=2)return t.slice(-2).join(".");return e}function _i(e,t){if(t.redis)Wi(e,t.redis);if(t.memcached)Gi(e,t.memcached);if(t.elasticache)Fi(e,t.elasticache)}function Wi(e,t){if(!t)return;if(e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache Redis cluster",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Redis",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:t.port||6379,ToPort:t.port||6379,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]}),t.parameterGroup&&Object.keys(t.parameterGroup).length>0)e.addResource("CacheParameterGroup","AWS::ElastiCache::ParameterGroup",{Description:"Parameter group for Redis",CacheParameterGroupFamily:`redis${t.engineVersion.split(".")[0]}`,Properties:t.parameterGroup});if(t.numCacheNodes>1||t.automaticFailoverEnabled)e.addResource("RedisReplicationGroup","AWS::ElastiCache::ReplicationGroup",{ReplicationGroupDescription:"Redis replication group",ReplicationGroupId:d.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheClusters:t.numCacheNodes,AutomaticFailoverEnabled:t.automaticFailoverEnabled||!1,MultiAZEnabled:t.automaticFailoverEnabled||!1,Port:t.port||6379,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),SecurityGroupIds:[d.ref("CacheSecurityGroup")],CacheParameterGroupName:t.parameterGroup?d.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:t.snapshotRetentionLimit||5,SnapshotWindow:t.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",AtRestEncryptionEnabled:!0,TransitEncryptionEnabled:!0,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-redis")}]},{dependsOn:t.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis primary endpoint",Value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address"),Export:{Name:d.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port"),Export:{Name:d.sub("${AWS::StackName}-redis-port")}}});else e.addResource("RedisCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:d.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheNodes:1,Port:t.port||6379,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[d.ref("CacheSecurityGroup")],CacheParameterGroupName:t.parameterGroup?d.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:t.snapshotRetentionLimit||5,SnapshotWindow:t.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-redis")}]},{dependsOn:t.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis endpoint",Value:d.getAtt("RedisCacheCluster","RedisEndpoint.Address"),Export:{Name:d.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:d.getAtt("RedisCacheCluster","RedisEndpoint.Port"),Export:{Name:d.sub("${AWS::StackName}-redis-port")}}})}function Gi(e,t){if(!t)return;if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Memcached",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:t.port||11211,ToPort:t.port||11211,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("MemcachedCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:d.sub("${AWS::StackName}-memcached"),Engine:"memcached",EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheNodes:t.numCacheNodes,Port:t.port||11211,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[d.ref("CacheSecurityGroup")],PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-memcached")}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]}),e.addOutputs({MemcachedEndpoint:{Description:"Memcached configuration endpoint",Value:d.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Address"),Export:{Name:d.sub("${AWS::StackName}-memcached-endpoint")}},MemcachedPort:{Description:"Memcached port",Value:d.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Port"),Export:{Name:d.sub("${AWS::StackName}-memcached-port")}}})}function Fi(e,t){if(!t)return;let a=t.engine==="redis";if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:a?6379:11211,ToPort:a?6379:11211,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("CacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:d.sub(`\${AWS::StackName}-${t.engine}`),Engine:t.engine,EngineVersion:t.engineVersion,CacheNodeType:t.nodeType,NumCacheNodes:t.numCacheNodes,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[d.ref("CacheSecurityGroup")],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.engine}`)}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]})}function Vi(e,t){if(!t.enabled)return;e.addResource("CloudFrontOriginAccessIdentity","AWS::CloudFront::CloudFrontOriginAccessIdentity",{CloudFrontOriginAccessIdentityConfig:{Comment:d.sub("${AWS::StackName} CloudFront OAI")}});let a=[],r=[];if(!t.origins||t.origins.length===0)a.push({Id:"S3Origin",DomainName:d.getAtt("StaticBucket","DomainName"),S3OriginConfig:{OriginAccessIdentity:d.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")}});else t.origins.forEach((s,o)=>{let c={Id:s.id,DomainName:s.domainName};if(s.originPath)c.OriginPath=s.originPath;if(s.domainName.includes("s3"))c.S3OriginConfig={OriginAccessIdentity:d.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")};else c.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"]};if(a.push(c),o>0||s.pathPattern)r.push({PathPattern:s.pathPattern||`/${s.id}/*`,TargetOriginId:s.id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:t.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:t.cachePolicy?.minTTL||0,DefaultTTL:t.cachePolicy?.defaultTTL||86400,MaxTTL:t.cachePolicy?.maxTTL||31536000})});let n={TargetOriginId:a[0].Id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:t.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:t.cachePolicy?.minTTL||0,DefaultTTL:t.cachePolicy?.defaultTTL||86400,MaxTTL:t.cachePolicy?.maxTTL||31536000};if(t.edgeFunctions&&t.edgeFunctions.length>0)n.LambdaFunctionAssociations=t.edgeFunctions.map((s)=>({EventType:s.eventType,LambdaFunctionARN:s.functionArn}));let i={Enabled:!0,HttpVersion:t.http3?"http3":"http2",IPV6Enabled:!0,Origins:a,DefaultCacheBehavior:n,PriceClass:t.priceClass||"PriceClass_100",ViewerCertificate:{}};if(r.length>0)i.CacheBehaviors=r;if(t.customDomain)i.Aliases=[t.customDomain.domain],i.ViewerCertificate={AcmCertificateArn:t.customDomain.certificateArn,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else i.ViewerCertificate={CloudFrontDefaultCertificate:!0};if(t.errorPages)i.CustomErrorResponses=Object.entries(t.errorPages).map(([s,o])=>({ErrorCode:Number.parseInt(s),ResponseCode:200,ResponsePagePath:o,ErrorCachingMinTTL:300}));if(i.DefaultRootObject="index.html",i.Comment=d.sub("${AWS::StackName} CloudFront Distribution"),e.addResource("CloudFrontDistribution","AWS::CloudFront::Distribution",{DistributionConfig:i},{dependsOn:"CloudFrontOriginAccessIdentity"}),!t.origins||t.origins.length===0)e.addResource("StaticBucketPolicyForCloudFront","AWS::S3::BucketPolicy",{Bucket:d.ref("StaticBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontAccess",Effect:"Allow",Principal:{CanonicalUser:d.getAtt("CloudFrontOriginAccessIdentity","S3CanonicalUserId")},Action:"s3:GetObject",Resource:d.join("",[d.getAtt("StaticBucket","Arn"),"/*"])}]}},{dependsOn:["StaticBucket","CloudFrontOriginAccessIdentity"]});if(t.customDomain)e.addResource("CloudFrontDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:d.sub(`${Ui(t.customDomain.domain)}.`),Name:t.customDomain.domain,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:d.getAtt("CloudFrontDistribution","DomainName"),EvaluateTargetHealth:!1}},{dependsOn:"CloudFrontDistribution"});if(e.addOutputs({CloudFrontDistributionId:{Description:"CloudFront distribution ID",Value:d.ref("CloudFrontDistribution"),Export:{Name:d.sub("${AWS::StackName}-cloudfront-id")}},CloudFrontDomainName:{Description:"CloudFront distribution domain name",Value:d.getAtt("CloudFrontDistribution","DomainName"),Export:{Name:d.sub("${AWS::StackName}-cloudfront-domain")}}}),t.customDomain)e.addOutputs({CloudFrontURL:{Description:"CloudFront custom domain URL",Value:d.sub(`https://${t.customDomain.domain}`)}})}function Ui(e){let t=e.split(".");if(t.length>=2)return t.slice(-2).join(".");return e}function ji(e,t){if(t.server)Ki(e,t.server);if(t.fargate)ga(e,"app",t.fargate);if(t.services)t.services.forEach((a)=>{if(a.type==="fargate")ga(e,a.name,{taskDefinition:a.taskDefinition,service:a.service})})}function Ki(e,t){if(!t)return;e.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for application instances",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:3000,ToPort:3000,SourceSecurityGroupId:d.ref("ALBSecurityGroup")},{IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:"0.0.0.0/0"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-app-sg")}]},{dependsOn:"VPC"}),e.addResource("EC2InstanceRole","AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ec2.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore","arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-ec2-role")}]}),e.addResource("EC2InstanceProfile","AWS::IAM::InstanceProfile",{Roles:[d.ref("EC2InstanceRole")]},{dependsOn:"EC2InstanceRole"});let a=t.userData||`#!/bin/bash
|
|
2469
2469
|
set -e
|
|
2470
2470
|
# Update system
|
|
2471
2471
|
yum update -y || apt-get update -y
|
|
@@ -2480,36 +2480,36 @@ rpm -U ./amazon-cloudwatch-agent.rpm || true
|
|
|
2480
2480
|
|
|
2481
2481
|
# Signal completion
|
|
2482
2482
|
/opt/aws/bin/cfn-signal -e $? --stack \${AWS::StackName} --resource AutoScalingGroup --region \${AWS::Region}
|
|
2483
|
-
`;if(e.addResource("LaunchTemplate","AWS::EC2::LaunchTemplate",{LaunchTemplateName:d.sub("${AWS::StackName}-template"),LaunchTemplateData:{ImageId:t.ami||d.findInMap("RegionMap",d.ref("AWS::Region"),"AMI"),InstanceType:t.instanceType,IamInstanceProfile:{Arn:d.getAtt("EC2InstanceProfile","Arn")},SecurityGroupIds:[d.ref("AppSecurityGroup")],UserData:d.base64(d.sub(a)),TagSpecifications:[{ResourceType:"instance",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-instance")}]}],MetadataOptions:{HttpTokens:"required",HttpPutResponseHopLimit:1}}},{dependsOn:["AppSecurityGroup","EC2InstanceProfile"]}),t.loadBalancer){Hi(e,t.loadBalancer);let r={LaunchTemplate:{LaunchTemplateId:d.ref("LaunchTemplate"),Version:d.getAtt("LaunchTemplate","LatestVersionNumber")},MinSize:t.autoScaling?.min.toString()||"1",MaxSize:t.autoScaling?.max.toString()||"3",DesiredCapacity:t.autoScaling?.min.toString()||"2",VPCZoneIdentifier:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],TargetGroupARNs:[d.ref("TargetGroup")],HealthCheckType:"ELB",HealthCheckGracePeriod:300,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-asg"),PropagateAtLaunch:!0}]};if(e.addResource("AutoScalingGroup","AWS::AutoScaling::AutoScalingGroup",r,{dependsOn:["LaunchTemplate","TargetGroup"]}),t.autoScaling)e.addResource("ScaleUpPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:d.ref("AutoScalingGroup"),Cooldown:t.autoScaling.scaleUpCooldown?.toString()||"300",ScalingAdjustment:"1"},{dependsOn:"AutoScalingGroup"}),e.addResource("ScaleDownPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:d.ref("AutoScalingGroup"),Cooldown:t.autoScaling.scaleDownCooldown?.toString()||"300",ScalingAdjustment:"-1"},{dependsOn:"AutoScalingGroup"}),e.addResource("HighCPUAlarm","AWS::CloudWatch::Alarm",{AlarmDescription:"Scale up when CPU exceeds target",MetricName:"CPUUtilization",Namespace:"AWS/EC2",Statistic:"Average",Period:"300",EvaluationPeriods:"2",Threshold:(t.autoScaling.targetCPU||70).toString(),AlarmActions:[d.ref("ScaleUpPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:d.ref("AutoScalingGroup")}],ComparisonOperator:"GreaterThanThreshold"},{dependsOn:["AutoScalingGroup","ScaleUpPolicy"]}),e.addResource("LowCPUAlarm","AWS::CloudWatch::Alarm",{AlarmDescription:"Scale down when CPU is below threshold",MetricName:"CPUUtilization",Namespace:"AWS/EC2",Statistic:"Average",Period:"300",EvaluationPeriods:"2",Threshold:((t.autoScaling.targetCPU||70)-20).toString(),AlarmActions:[d.ref("ScaleDownPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:d.ref("AutoScalingGroup")}],ComparisonOperator:"LessThanThreshold"},{dependsOn:["AutoScalingGroup","ScaleDownPolicy"]})}}function Hi(e,t){if(!t)return;e.addResource("ALBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for Application Load Balancer",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-alb-sg")}]},{dependsOn:"VPC"}),e.addResource("LoadBalancer","AWS::ElasticLoadBalancingV2::LoadBalancer",{Name:d.sub("${AWS::StackName}-alb"),Type:t.type||"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[d.ref("PublicSubnet1"),d.ref("PublicSubnet2")],SecurityGroups:[d.ref("ALBSecurityGroup")],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-alb")}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]}),e.addResource("TargetGroup","AWS::ElasticLoadBalancingV2::TargetGroup",{Name:d.sub("${AWS::StackName}-tg"),Port:3000,Protocol:"HTTP",VpcId:d.ref("VPC"),HealthCheckEnabled:!0,HealthCheckPath:t.healthCheck?.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:t.healthCheck?.interval||30,HealthCheckTimeoutSeconds:t.healthCheck?.timeout||5,HealthyThresholdCount:t.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:t.healthCheck?.unhealthyThreshold||3,TargetType:"instance",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-tg")}]},{dependsOn:"VPC"}),e.addResource("LoadBalancerListener","AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:d.ref("LoadBalancer"),Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:d.ref("TargetGroup")}]},{dependsOn:["LoadBalancer","TargetGroup"]}),e.addOutputs({LoadBalancerDNS:{Description:"Load Balancer DNS Name",Value:d.getAtt("LoadBalancer","DNSName"),Export:{Name:d.sub("${AWS::StackName}-alb-dns")}}})}function pa(e,t,a){let r=e.toLogicalId(t),n=a.taskDefinition.containerDefinitions?.[0],i=n?.name||n?.Name||t,s=n?.portMappings?.[0]?.containerPort||n?.PortMappings?.[0]?.ContainerPort||3000,o=(a.taskDefinition.containerDefinitions||[]).flatMap((p)=>(p.secrets||p.Secrets||[]).map((g)=>g.valueFrom||g.ValueFrom)).filter(Boolean);if(!e.hasResource("ECSCluster"))e.addResource("ECSCluster","AWS::ECS::Cluster",{ClusterName:d.sub("${AWS::StackName}-cluster"),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cluster")}]});if(e.addResource(`${r}TaskExecutionRole`,"AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"],...o.length?{Policies:[{PolicyName:"read-task-secrets",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameters"],Resource:o},{Effect:"Allow",Action:"kms:Decrypt",Resource:"*"}]}}]}:{}}),e.addResource(`${r}TaskRole`,"AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"application-services",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:SendMessage"],Resource:d.sub("arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:${AWS::StackName}-*")},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:"*"}]}}]}),!e.hasResource("ALBSecurityGroup"))e.addResource("ALBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Public ingress for the application load balancer",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0"},...a.loadBalancer?.customDomain?.certificateArn?[{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0"}]:[]],SecurityGroupEgress:[{IpProtocol:"tcp",FromPort:s,ToPort:s,CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-alb-sg")}]},{dependsOn:"VPC"});if(!e.hasResource("AppSecurityGroup"))e.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Only the application load balancer may reach Fargate tasks",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:s,ToPort:s,SourceSecurityGroupId:d.ref("ALBSecurityGroup")}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-app-sg")}]},{dependsOn:["VPC","ALBSecurityGroup"]});let c=(a.taskDefinition.containerDefinitions||[{name:t,image:d.sub(`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${t}:latest`),portMappings:[{containerPort:3000}]}]).map((p)=>({Name:p.Name||p.name,Image:p.Image||p.image,Essential:p.Essential??p.essential??!0,PortMappings:(p.PortMappings||p.portMappings||[]).map((g)=>({ContainerPort:g.ContainerPort??g.containerPort,Protocol:g.Protocol||g.protocol||"tcp"})),Environment:Array.isArray(p.Environment||p.environment)?(p.Environment||p.environment).map((g)=>({Name:g.Name||g.name,Value:g.Value??g.value})):Object.entries(p.Environment||p.environment||{}).map(([g,h])=>({Name:g,Value:h})),Secrets:(p.Secrets||p.secrets||[]).map((g)=>({Name:g.Name||g.name,ValueFrom:g.ValueFrom||g.valueFrom})),HealthCheck:p.HealthCheck||p.healthCheck,Command:p.Command||p.command,EntryPoint:p.EntryPoint||p.entryPoint,LogConfiguration:p.LogConfiguration||p.logConfiguration||{LogDriver:"awslogs",Options:{"awslogs-group":d.ref(`${r}LogGroup`),"awslogs-region":d.ref("AWS::Region"),"awslogs-stream-prefix":t}}}));e.addResource(`${r}TaskDefinition`,"AWS::ECS::TaskDefinition",{Family:d.sub(`\${AWS::StackName}-${t}`),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:a.taskDefinition.cpu,Memory:a.taskDefinition.memory,ExecutionRoleArn:d.getAtt(`${r}TaskExecutionRole`,"Arn"),TaskRoleArn:d.getAtt(`${r}TaskRole`,"Arn"),ContainerDefinitions:c},{dependsOn:[`${r}TaskExecutionRole`,`${r}TaskRole`,`${r}LogGroup`]}),e.addResource(`${r}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:d.sub(`/ecs/\${AWS::StackName}/${t}`),RetentionInDays:14});let l=a.service.healthCheck||{};e.addResource(`${r}TargetGroup`,"AWS::ElasticLoadBalancingV2::TargetGroup",{VpcId:d.ref("VPC"),Port:s,Protocol:"HTTP",TargetType:"ip",HealthCheckEnabled:!0,HealthCheckPath:l.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:l.interval||30,HealthCheckTimeoutSeconds:l.timeout||5,HealthyThresholdCount:l.healthyThreshold||2,UnhealthyThresholdCount:l.unhealthyThreshold||3,Matcher:{HttpCode:"200-399"},TargetGroupAttributes:[{Key:"deregistration_delay.timeout_seconds",Value:"30"}]},{dependsOn:"VPC"}),e.addResource(`${r}LoadBalancer`,"AWS::ElasticLoadBalancingV2::LoadBalancer",{Type:"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[d.ref("PublicSubnet1"),d.ref("PublicSubnet2")],SecurityGroups:[d.ref("ALBSecurityGroup")],LoadBalancerAttributes:[{Key:"routing.http.drop_invalid_header_fields.enabled",Value:"true"},{Key:"deletion_protection.enabled",Value:String(a.loadBalancer?.deletionProtection===!0)}],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}-alb`)}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]});let u=a.loadBalancer?.customDomain?.certificateArn,m=a.loadBalancer?.originVerifyHeader;if(e.addResource(`${r}HttpListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:d.ref(`${r}LoadBalancer`),Port:80,Protocol:"HTTP",DefaultActions:u?[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]:m?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:d.ref(`${r}TargetGroup`)}]},{dependsOn:[`${r}LoadBalancer`,`${r}TargetGroup`]}),u)e.addResource(`${r}HttpsListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:d.ref(`${r}LoadBalancer`),Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:u}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06",DefaultActions:m?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:d.ref(`${r}TargetGroup`)}]},{dependsOn:[`${r}LoadBalancer`,`${r}TargetGroup`]});if(m){let p=u?`${r}HttpsListener`:`${r}HttpListener`;e.addResource(`${r}OriginVerifyRule`,"AWS::ElasticLoadBalancingV2::ListenerRule",{ListenerArn:d.ref(p),Priority:1,Conditions:[{Field:"http-header",HttpHeaderConfig:{HttpHeaderName:m.name,Values:[m.value]}}],Actions:[{Type:"forward",TargetGroupArn:d.ref(`${r}TargetGroup`)}]},{dependsOn:[p,`${r}TargetGroup`]})}if(e.addResource(`${r}Service`,"AWS::ECS::Service",{ServiceName:d.sub(`\${AWS::StackName}-${t}`),Cluster:d.ref("ECSCluster"),TaskDefinition:d.ref(`${r}TaskDefinition`),DesiredCount:a.service.desiredCount,LaunchType:"FARGATE",PlatformVersion:"LATEST",HealthCheckGracePeriodSeconds:60,DeploymentConfiguration:{MinimumHealthyPercent:100,MaximumPercent:200,DeploymentCircuitBreaker:{Enable:!0,Rollback:!0}},LoadBalancers:[{ContainerName:i,ContainerPort:s,TargetGroupArn:d.ref(`${r}TargetGroup`)}],NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"DISABLED",Subnets:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],SecurityGroups:[d.ref("AppSecurityGroup")]}}},{dependsOn:["ECSCluster",`${r}TaskDefinition`,m?`${r}OriginVerifyRule`:u?`${r}HttpsListener`:`${r}HttpListener`]}),a.service.autoScaling){let p=a.service.autoScaling;e.addResource(`${r}ScalableTarget`,"AWS::ApplicationAutoScaling::ScalableTarget",{MinCapacity:p.min,MaxCapacity:p.max,ResourceId:d.join("/",["service",d.ref("ECSCluster"),d.getAtt(`${r}Service`,"Name")]),RoleARN:d.sub("arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"),ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs"},{dependsOn:`${r}Service`}),e.addResource(`${r}ScalingPolicy`,"AWS::ApplicationAutoScaling::ScalingPolicy",{PolicyType:"TargetTrackingScaling",ScalingTargetId:d.ref(`${r}ScalableTarget`),TargetTrackingScalingPolicyConfiguration:{TargetValue:p.targetCPU||70,PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},ScaleInCooldown:60,ScaleOutCooldown:30}},{dependsOn:`${r}ScalableTarget`})}e.addOutputs({[`${r}ClusterName`]:{Description:"ECS cluster name",Value:d.ref("ECSCluster")},[`${r}ServiceName`]:{Description:"ECS service name",Value:d.getAtt(`${r}Service`,"Name")},[`${r}LoadBalancerDnsName`]:{Description:"ALB origin hostname",Value:d.getAtt(`${r}LoadBalancer`,"DNSName")},[`${r}LoadBalancerHostedZoneId`]:{Description:"ALB canonical hosted zone ID",Value:d.getAtt(`${r}LoadBalancer`,"CanonicalHostedZoneID")},[`${r}TargetGroupArn`]:{Description:"ECS target group ARN",Value:d.ref(`${r}TargetGroup`)}})}function qi(e,t){if(t.postgres)ga(e,"postgres",t.postgres);if(t.mysql)ga(e,"mysql",t.mysql);if(t.dynamodb?.tables)t.dynamodb.tables.forEach((a)=>{zi(e,a)})}function ga(e,t,a){if(!a)return;let r=t==="postgres"?"postgres":"mysql",n=e.toLogicalId(`${r}-db`);e.addResource("DBSubnetGroup","AWS::RDS::DBSubnetGroup",{DBSubnetGroupDescription:"Subnet group for RDS instance",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-db-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("DBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for RDS instance",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:t==="postgres"?5432:3306,ToPort:t==="postgres"?5432:3306,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-db-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});let i=t==="postgres"?`postgres${a.version.split(".")[0]}`:`mysql${a.version.split(".")[0]}.${a.version.split(".")[1]||"0"}`;if(a.parameters&&Object.keys(a.parameters).length>0)e.addResource("DBParameterGroup","AWS::RDS::DBParameterGroup",{Description:`Parameter group for ${r}`,Family:i,Parameters:a.parameters,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-db-params")}]});e.addResource("DBSecret","AWS::SecretsManager::Secret",{Description:"Database credentials",GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"admin"}),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\'},Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-db-secret")}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"});let s={Engine:r,EngineVersion:a.version,DBInstanceClass:a.instanceClass,AllocatedStorage:a.allocatedStorage.toString(),MaxAllocatedStorage:a.maxAllocatedStorage?.toString(),StorageType:"gp3",StorageEncrypted:!0,MultiAZ:a.multiAZ!==!1,DBSubnetGroupName:d.ref("DBSubnetGroup"),VPCSecurityGroups:[d.ref("DBSecurityGroup")],MasterUsername:d.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:username}}"),MasterUserPassword:d.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:password}}"),BackupRetentionPeriod:a.backupRetentionDays||7,PreferredBackupWindow:a.preferredBackupWindow||"03:00-04:00",PreferredMaintenanceWindow:a.preferredMaintenanceWindow||"sun:04:00-sun:05:00",EnablePerformanceInsights:a.enablePerformanceInsights!==!1,PerformanceInsightsRetentionPeriod:a.performanceInsightsRetention||7,DeletionProtection:a.deletionProtection!==!1,CopyTagsToSnapshot:!0,EnableCloudwatchLogsExports:t==="postgres"?["postgresql"]:["error","general","slowquery"],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${r}-db`)}]};if(a.parameters&&Object.keys(a.parameters).length>0)s.DBParameterGroupName=d.ref("DBParameterGroup");e.addResource(n,"AWS::RDS::DBInstance",s,{dependsOn:["DBSubnetGroup","DBSecurityGroup","DBSecret"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addResource("DBSecretAttachment","AWS::SecretsManager::SecretTargetAttachment",{SecretId:d.ref("DBSecret"),TargetId:d.ref(n),TargetType:"AWS::RDS::DBInstance"},{dependsOn:[n,"DBSecret"]}),e.addOutputs({DBEndpoint:{Description:"Database endpoint",Value:d.getAtt(n,"Endpoint.Address"),Export:{Name:d.sub("${AWS::StackName}-db-endpoint")}},DBPort:{Description:"Database port",Value:d.getAtt(n,"Endpoint.Port"),Export:{Name:d.sub("${AWS::StackName}-db-port")}},DBSecretArn:{Description:"ARN of the database credentials secret",Value:d.ref("DBSecret"),Export:{Name:d.sub("${AWS::StackName}-db-secret-arn")}}})}function zi(e,t){let a=e.toLogicalId(`${t.name}-table`),r={TableName:d.sub(`\${AWS::StackName}-${t.name}`),BillingMode:t.billingMode||"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:t.partitionKey,AttributeType:"S"}],KeySchema:[{AttributeName:t.partitionKey,KeyType:"HASH"}],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}`)}]};if(t.sortKey)r.AttributeDefinitions.push({AttributeName:t.sortKey,AttributeType:"S"}),r.KeySchema.push({AttributeName:t.sortKey,KeyType:"RANGE"});if(t.billingMode==="PROVISIONED")r.ProvisionedThroughput={ReadCapacityUnits:t.readCapacity||5,WriteCapacityUnits:t.writeCapacity||5};if(t.streamEnabled)r.StreamSpecification={StreamViewType:"NEW_AND_OLD_IMAGES"};if(t.pointInTimeRecovery)r.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(t.ttl?.enabled)r.TimeToLiveSpecification={Enabled:!0,AttributeName:t.ttl.attributeName};if(t.globalSecondaryIndexes&&t.globalSecondaryIndexes.length>0)r.GlobalSecondaryIndexes=t.globalSecondaryIndexes.map((n)=>{let i=new Set(r.AttributeDefinitions.map((o)=>o.AttributeName));if(!i.has(n.partitionKey))r.AttributeDefinitions.push({AttributeName:n.partitionKey,AttributeType:"S"});if(n.sortKey&&!i.has(n.sortKey))r.AttributeDefinitions.push({AttributeName:n.sortKey,AttributeType:"S"});let s={IndexName:n.name,KeySchema:[{AttributeName:n.partitionKey,KeyType:"HASH"}],Projection:{ProjectionType:n.projectionType||"ALL"}};if(n.sortKey)s.KeySchema.push({AttributeName:n.sortKey,KeyType:"RANGE"});if(n.projectionType==="INCLUDE"&&n.nonKeyAttributes)s.Projection.NonKeyAttributes=n.nonKeyAttributes;if(t.billingMode==="PROVISIONED")s.ProvisionedThroughput={ReadCapacityUnits:t.readCapacity||5,WriteCapacityUnits:t.writeCapacity||5};return s});if(e.addResource(a,"AWS::DynamoDB::Table",r,{deletionPolicy:"Retain"}),e.addOutputs({[`${a}Name`]:{Description:`${t.name} table name`,Value:d.ref(a),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-table`)}},[`${a}Arn`]:{Description:`${t.name} table ARN`,Value:d.getAtt(a,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-table-arn`)}}}),t.streamEnabled)e.addOutputs({[`${a}StreamArn`]:{Description:`${t.name} stream ARN`,Value:d.getAtt(a,"StreamArn"),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-stream-arn`)}}})}function Ji(e,t){for(let[a,r]of Object.entries(t))r.forEach((n)=>{Qi(e,n,a)})}function Qi(e,t,a){let r=e.toLogicalId(`${a}-${t.name}-function`),n=`${r}Role`;e.addResource(n,"AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole","arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"],Policies:[{PolicyName:"LambdaExecutionPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[...Yi(t.events||[])]}}],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}-role`)}]});let i={FunctionName:d.sub(`\${AWS::StackName}-${t.name}`),Runtime:t.runtime,Handler:t.handler,Role:d.getAtt(n,"Arn"),MemorySize:t.memory,Timeout:t.timeout,Code:{ZipFile:`exports.handler = async (event) => {
|
|
2483
|
+
`;if(e.addResource("LaunchTemplate","AWS::EC2::LaunchTemplate",{LaunchTemplateName:d.sub("${AWS::StackName}-template"),LaunchTemplateData:{ImageId:t.ami||d.findInMap("RegionMap",d.ref("AWS::Region"),"AMI"),InstanceType:t.instanceType,IamInstanceProfile:{Arn:d.getAtt("EC2InstanceProfile","Arn")},SecurityGroupIds:[d.ref("AppSecurityGroup")],UserData:d.base64(d.sub(a)),TagSpecifications:[{ResourceType:"instance",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-instance")}]}],MetadataOptions:{HttpTokens:"required",HttpPutResponseHopLimit:1}}},{dependsOn:["AppSecurityGroup","EC2InstanceProfile"]}),t.loadBalancer){Hi(e,t.loadBalancer);let r={LaunchTemplate:{LaunchTemplateId:d.ref("LaunchTemplate"),Version:d.getAtt("LaunchTemplate","LatestVersionNumber")},MinSize:t.autoScaling?.min.toString()||"1",MaxSize:t.autoScaling?.max.toString()||"3",DesiredCapacity:t.autoScaling?.min.toString()||"2",VPCZoneIdentifier:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],TargetGroupARNs:[d.ref("TargetGroup")],HealthCheckType:"ELB",HealthCheckGracePeriod:300,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-asg"),PropagateAtLaunch:!0}]};if(e.addResource("AutoScalingGroup","AWS::AutoScaling::AutoScalingGroup",r,{dependsOn:["LaunchTemplate","TargetGroup"]}),t.autoScaling)e.addResource("ScaleUpPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:d.ref("AutoScalingGroup"),Cooldown:t.autoScaling.scaleUpCooldown?.toString()||"300",ScalingAdjustment:"1"},{dependsOn:"AutoScalingGroup"}),e.addResource("ScaleDownPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:d.ref("AutoScalingGroup"),Cooldown:t.autoScaling.scaleDownCooldown?.toString()||"300",ScalingAdjustment:"-1"},{dependsOn:"AutoScalingGroup"}),e.addResource("HighCPUAlarm","AWS::CloudWatch::Alarm",{AlarmDescription:"Scale up when CPU exceeds target",MetricName:"CPUUtilization",Namespace:"AWS/EC2",Statistic:"Average",Period:"300",EvaluationPeriods:"2",Threshold:(t.autoScaling.targetCPU||70).toString(),AlarmActions:[d.ref("ScaleUpPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:d.ref("AutoScalingGroup")}],ComparisonOperator:"GreaterThanThreshold"},{dependsOn:["AutoScalingGroup","ScaleUpPolicy"]}),e.addResource("LowCPUAlarm","AWS::CloudWatch::Alarm",{AlarmDescription:"Scale down when CPU is below threshold",MetricName:"CPUUtilization",Namespace:"AWS/EC2",Statistic:"Average",Period:"300",EvaluationPeriods:"2",Threshold:((t.autoScaling.targetCPU||70)-20).toString(),AlarmActions:[d.ref("ScaleDownPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:d.ref("AutoScalingGroup")}],ComparisonOperator:"LessThanThreshold"},{dependsOn:["AutoScalingGroup","ScaleDownPolicy"]})}}function Hi(e,t){if(!t)return;e.addResource("ALBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for Application Load Balancer",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-alb-sg")}]},{dependsOn:"VPC"}),e.addResource("LoadBalancer","AWS::ElasticLoadBalancingV2::LoadBalancer",{Name:d.sub("${AWS::StackName}-alb"),Type:t.type||"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[d.ref("PublicSubnet1"),d.ref("PublicSubnet2")],SecurityGroups:[d.ref("ALBSecurityGroup")],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-alb")}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]}),e.addResource("TargetGroup","AWS::ElasticLoadBalancingV2::TargetGroup",{Name:d.sub("${AWS::StackName}-tg"),Port:3000,Protocol:"HTTP",VpcId:d.ref("VPC"),HealthCheckEnabled:!0,HealthCheckPath:t.healthCheck?.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:t.healthCheck?.interval||30,HealthCheckTimeoutSeconds:t.healthCheck?.timeout||5,HealthyThresholdCount:t.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:t.healthCheck?.unhealthyThreshold||3,TargetType:"instance",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-tg")}]},{dependsOn:"VPC"}),e.addResource("LoadBalancerListener","AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:d.ref("LoadBalancer"),Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:d.ref("TargetGroup")}]},{dependsOn:["LoadBalancer","TargetGroup"]}),e.addOutputs({LoadBalancerDNS:{Description:"Load Balancer DNS Name",Value:d.getAtt("LoadBalancer","DNSName"),Export:{Name:d.sub("${AWS::StackName}-alb-dns")}}})}function ga(e,t,a){let r=e.toLogicalId(t),n=a.taskDefinition.containerDefinitions?.[0],i=n?.name||n?.Name||t,s=n?.portMappings?.[0]?.containerPort||n?.PortMappings?.[0]?.ContainerPort||3000,o=(a.taskDefinition.containerDefinitions||[]).flatMap((p)=>(p.secrets||p.Secrets||[]).map((g)=>g.valueFrom||g.ValueFrom)).filter(Boolean);if(!e.hasResource("ECSCluster"))e.addResource("ECSCluster","AWS::ECS::Cluster",{ClusterName:d.sub("${AWS::StackName}-cluster"),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-cluster")}]});if(e.addResource(`${r}TaskExecutionRole`,"AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"],...o.length?{Policies:[{PolicyName:"read-task-secrets",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameters"],Resource:o},{Effect:"Allow",Action:"kms:Decrypt",Resource:"*"}]}}]}:{}}),e.addResource(`${r}TaskRole`,"AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"application-services",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:SendMessage"],Resource:d.sub("arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:${AWS::StackName}-*")},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:"*"}]}}]}),!e.hasResource("ALBSecurityGroup"))e.addResource("ALBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Public ingress for the application load balancer",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0"},...a.loadBalancer?.customDomain?.certificateArn?[{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0"}]:[]],SecurityGroupEgress:[{IpProtocol:"tcp",FromPort:s,ToPort:s,CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-alb-sg")}]},{dependsOn:"VPC"});if(!e.hasResource("AppSecurityGroup"))e.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Only the application load balancer may reach Fargate tasks",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:s,ToPort:s,SourceSecurityGroupId:d.ref("ALBSecurityGroup")}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-app-sg")}]},{dependsOn:["VPC","ALBSecurityGroup"]});let c=(a.taskDefinition.containerDefinitions||[{name:t,image:d.sub(`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${t}:latest`),portMappings:[{containerPort:3000}]}]).map((p)=>({Name:p.Name||p.name,Image:p.Image||p.image,Essential:p.Essential??p.essential??!0,PortMappings:(p.PortMappings||p.portMappings||[]).map((g)=>({ContainerPort:g.ContainerPort??g.containerPort,Protocol:g.Protocol||g.protocol||"tcp"})),Environment:Array.isArray(p.Environment||p.environment)?(p.Environment||p.environment).map((g)=>({Name:g.Name||g.name,Value:g.Value??g.value})):Object.entries(p.Environment||p.environment||{}).map(([g,h])=>({Name:g,Value:h})),Secrets:(p.Secrets||p.secrets||[]).map((g)=>({Name:g.Name||g.name,ValueFrom:g.ValueFrom||g.valueFrom})),HealthCheck:p.HealthCheck||p.healthCheck,Command:p.Command||p.command,EntryPoint:p.EntryPoint||p.entryPoint,LogConfiguration:p.LogConfiguration||p.logConfiguration||{LogDriver:"awslogs",Options:{"awslogs-group":d.ref(`${r}LogGroup`),"awslogs-region":d.ref("AWS::Region"),"awslogs-stream-prefix":t}}}));e.addResource(`${r}TaskDefinition`,"AWS::ECS::TaskDefinition",{Family:d.sub(`\${AWS::StackName}-${t}`),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:a.taskDefinition.cpu,Memory:a.taskDefinition.memory,ExecutionRoleArn:d.getAtt(`${r}TaskExecutionRole`,"Arn"),TaskRoleArn:d.getAtt(`${r}TaskRole`,"Arn"),ContainerDefinitions:c},{dependsOn:[`${r}TaskExecutionRole`,`${r}TaskRole`,`${r}LogGroup`]}),e.addResource(`${r}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:d.sub(`/ecs/\${AWS::StackName}/${t}`),RetentionInDays:14});let l=a.service.healthCheck||{};e.addResource(`${r}TargetGroup`,"AWS::ElasticLoadBalancingV2::TargetGroup",{VpcId:d.ref("VPC"),Port:s,Protocol:"HTTP",TargetType:"ip",HealthCheckEnabled:!0,HealthCheckPath:l.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:l.interval||30,HealthCheckTimeoutSeconds:l.timeout||5,HealthyThresholdCount:l.healthyThreshold||2,UnhealthyThresholdCount:l.unhealthyThreshold||3,Matcher:{HttpCode:"200-399"},TargetGroupAttributes:[{Key:"deregistration_delay.timeout_seconds",Value:"30"}]},{dependsOn:"VPC"}),e.addResource(`${r}LoadBalancer`,"AWS::ElasticLoadBalancingV2::LoadBalancer",{Type:"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[d.ref("PublicSubnet1"),d.ref("PublicSubnet2")],SecurityGroups:[d.ref("ALBSecurityGroup")],LoadBalancerAttributes:[{Key:"routing.http.drop_invalid_header_fields.enabled",Value:"true"},{Key:"deletion_protection.enabled",Value:String(a.loadBalancer?.deletionProtection===!0)}],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}-alb`)}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]});let u=a.loadBalancer?.customDomain?.certificateArn,m=a.loadBalancer?.originVerifyHeader;if(e.addResource(`${r}HttpListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:d.ref(`${r}LoadBalancer`),Port:80,Protocol:"HTTP",DefaultActions:u?[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]:m?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:d.ref(`${r}TargetGroup`)}]},{dependsOn:[`${r}LoadBalancer`,`${r}TargetGroup`]}),u)e.addResource(`${r}HttpsListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:d.ref(`${r}LoadBalancer`),Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:u}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06",DefaultActions:m?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:d.ref(`${r}TargetGroup`)}]},{dependsOn:[`${r}LoadBalancer`,`${r}TargetGroup`]});if(m){let p=u?`${r}HttpsListener`:`${r}HttpListener`;e.addResource(`${r}OriginVerifyRule`,"AWS::ElasticLoadBalancingV2::ListenerRule",{ListenerArn:d.ref(p),Priority:1,Conditions:[{Field:"http-header",HttpHeaderConfig:{HttpHeaderName:m.name,Values:[m.value]}}],Actions:[{Type:"forward",TargetGroupArn:d.ref(`${r}TargetGroup`)}]},{dependsOn:[p,`${r}TargetGroup`]})}if(e.addResource(`${r}Service`,"AWS::ECS::Service",{ServiceName:d.sub(`\${AWS::StackName}-${t}`),Cluster:d.ref("ECSCluster"),TaskDefinition:d.ref(`${r}TaskDefinition`),DesiredCount:a.service.desiredCount,LaunchType:"FARGATE",PlatformVersion:"LATEST",HealthCheckGracePeriodSeconds:60,DeploymentConfiguration:{MinimumHealthyPercent:100,MaximumPercent:200,DeploymentCircuitBreaker:{Enable:!0,Rollback:!0}},LoadBalancers:[{ContainerName:i,ContainerPort:s,TargetGroupArn:d.ref(`${r}TargetGroup`)}],NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"DISABLED",Subnets:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],SecurityGroups:[d.ref("AppSecurityGroup")]}}},{dependsOn:["ECSCluster",`${r}TaskDefinition`,m?`${r}OriginVerifyRule`:u?`${r}HttpsListener`:`${r}HttpListener`]}),a.service.autoScaling){let p=a.service.autoScaling;e.addResource(`${r}ScalableTarget`,"AWS::ApplicationAutoScaling::ScalableTarget",{MinCapacity:p.min,MaxCapacity:p.max,ResourceId:d.join("/",["service",d.ref("ECSCluster"),d.getAtt(`${r}Service`,"Name")]),RoleARN:d.sub("arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"),ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs"},{dependsOn:`${r}Service`}),e.addResource(`${r}ScalingPolicy`,"AWS::ApplicationAutoScaling::ScalingPolicy",{PolicyType:"TargetTrackingScaling",ScalingTargetId:d.ref(`${r}ScalableTarget`),TargetTrackingScalingPolicyConfiguration:{TargetValue:p.targetCPU||70,PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},ScaleInCooldown:60,ScaleOutCooldown:30}},{dependsOn:`${r}ScalableTarget`})}e.addOutputs({[`${r}ClusterName`]:{Description:"ECS cluster name",Value:d.ref("ECSCluster")},[`${r}ServiceName`]:{Description:"ECS service name",Value:d.getAtt(`${r}Service`,"Name")},[`${r}LoadBalancerDnsName`]:{Description:"ALB origin hostname",Value:d.getAtt(`${r}LoadBalancer`,"DNSName")},[`${r}LoadBalancerHostedZoneId`]:{Description:"ALB canonical hosted zone ID",Value:d.getAtt(`${r}LoadBalancer`,"CanonicalHostedZoneID")},[`${r}TargetGroupArn`]:{Description:"ECS target group ARN",Value:d.ref(`${r}TargetGroup`)}})}function qi(e,t){if(t.postgres)ha(e,"postgres",t.postgres);if(t.mysql)ha(e,"mysql",t.mysql);if(t.dynamodb?.tables)t.dynamodb.tables.forEach((a)=>{zi(e,a)})}function ha(e,t,a){if(!a)return;let r=t==="postgres"?"postgres":"mysql",n=e.toLogicalId(`${r}-db`);e.addResource("DBSubnetGroup","AWS::RDS::DBSubnetGroup",{DBSubnetGroupDescription:"Subnet group for RDS instance",SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-db-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("DBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for RDS instance",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:t==="postgres"?5432:3306,ToPort:t==="postgres"?5432:3306,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-db-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});let i=t==="postgres"?`postgres${a.version.split(".")[0]}`:`mysql${a.version.split(".")[0]}.${a.version.split(".")[1]||"0"}`;if(a.parameters&&Object.keys(a.parameters).length>0)e.addResource("DBParameterGroup","AWS::RDS::DBParameterGroup",{Description:`Parameter group for ${r}`,Family:i,Parameters:a.parameters,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-db-params")}]});e.addResource("DBSecret","AWS::SecretsManager::Secret",{Description:"Database credentials",GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"admin"}),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\'},Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-db-secret")}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"});let s={Engine:r,EngineVersion:a.version,DBInstanceClass:a.instanceClass,AllocatedStorage:a.allocatedStorage.toString(),MaxAllocatedStorage:a.maxAllocatedStorage?.toString(),StorageType:"gp3",StorageEncrypted:!0,MultiAZ:a.multiAZ!==!1,DBSubnetGroupName:d.ref("DBSubnetGroup"),VPCSecurityGroups:[d.ref("DBSecurityGroup")],MasterUsername:d.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:username}}"),MasterUserPassword:d.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:password}}"),BackupRetentionPeriod:a.backupRetentionDays||7,PreferredBackupWindow:a.preferredBackupWindow||"03:00-04:00",PreferredMaintenanceWindow:a.preferredMaintenanceWindow||"sun:04:00-sun:05:00",EnablePerformanceInsights:a.enablePerformanceInsights!==!1,PerformanceInsightsRetentionPeriod:a.performanceInsightsRetention||7,DeletionProtection:a.deletionProtection!==!1,CopyTagsToSnapshot:!0,EnableCloudwatchLogsExports:t==="postgres"?["postgresql"]:["error","general","slowquery"],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${r}-db`)}]};if(a.parameters&&Object.keys(a.parameters).length>0)s.DBParameterGroupName=d.ref("DBParameterGroup");e.addResource(n,"AWS::RDS::DBInstance",s,{dependsOn:["DBSubnetGroup","DBSecurityGroup","DBSecret"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addResource("DBSecretAttachment","AWS::SecretsManager::SecretTargetAttachment",{SecretId:d.ref("DBSecret"),TargetId:d.ref(n),TargetType:"AWS::RDS::DBInstance"},{dependsOn:[n,"DBSecret"]}),e.addOutputs({DBEndpoint:{Description:"Database endpoint",Value:d.getAtt(n,"Endpoint.Address"),Export:{Name:d.sub("${AWS::StackName}-db-endpoint")}},DBPort:{Description:"Database port",Value:d.getAtt(n,"Endpoint.Port"),Export:{Name:d.sub("${AWS::StackName}-db-port")}},DBSecretArn:{Description:"ARN of the database credentials secret",Value:d.ref("DBSecret"),Export:{Name:d.sub("${AWS::StackName}-db-secret-arn")}}})}function zi(e,t){let a=e.toLogicalId(`${t.name}-table`),r={TableName:d.sub(`\${AWS::StackName}-${t.name}`),BillingMode:t.billingMode||"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:t.partitionKey,AttributeType:"S"}],KeySchema:[{AttributeName:t.partitionKey,KeyType:"HASH"}],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}`)}]};if(t.sortKey)r.AttributeDefinitions.push({AttributeName:t.sortKey,AttributeType:"S"}),r.KeySchema.push({AttributeName:t.sortKey,KeyType:"RANGE"});if(t.billingMode==="PROVISIONED")r.ProvisionedThroughput={ReadCapacityUnits:t.readCapacity||5,WriteCapacityUnits:t.writeCapacity||5};if(t.streamEnabled)r.StreamSpecification={StreamViewType:"NEW_AND_OLD_IMAGES"};if(t.pointInTimeRecovery)r.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(t.ttl?.enabled)r.TimeToLiveSpecification={Enabled:!0,AttributeName:t.ttl.attributeName};if(t.globalSecondaryIndexes&&t.globalSecondaryIndexes.length>0)r.GlobalSecondaryIndexes=t.globalSecondaryIndexes.map((n)=>{let i=new Set(r.AttributeDefinitions.map((o)=>o.AttributeName));if(!i.has(n.partitionKey))r.AttributeDefinitions.push({AttributeName:n.partitionKey,AttributeType:"S"});if(n.sortKey&&!i.has(n.sortKey))r.AttributeDefinitions.push({AttributeName:n.sortKey,AttributeType:"S"});let s={IndexName:n.name,KeySchema:[{AttributeName:n.partitionKey,KeyType:"HASH"}],Projection:{ProjectionType:n.projectionType||"ALL"}};if(n.sortKey)s.KeySchema.push({AttributeName:n.sortKey,KeyType:"RANGE"});if(n.projectionType==="INCLUDE"&&n.nonKeyAttributes)s.Projection.NonKeyAttributes=n.nonKeyAttributes;if(t.billingMode==="PROVISIONED")s.ProvisionedThroughput={ReadCapacityUnits:t.readCapacity||5,WriteCapacityUnits:t.writeCapacity||5};return s});if(e.addResource(a,"AWS::DynamoDB::Table",r,{deletionPolicy:"Retain"}),e.addOutputs({[`${a}Name`]:{Description:`${t.name} table name`,Value:d.ref(a),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-table`)}},[`${a}Arn`]:{Description:`${t.name} table ARN`,Value:d.getAtt(a,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-table-arn`)}}}),t.streamEnabled)e.addOutputs({[`${a}StreamArn`]:{Description:`${t.name} stream ARN`,Value:d.getAtt(a,"StreamArn"),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-stream-arn`)}}})}function Qi(e,t){for(let[a,r]of Object.entries(t))r.forEach((n)=>{Ji(e,n,a)})}function Ji(e,t,a){let r=e.toLogicalId(`${a}-${t.name}-function`),n=`${r}Role`;e.addResource(n,"AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole","arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"],Policies:[{PolicyName:"LambdaExecutionPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[...Zi(t.events||[])]}}],Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}-role`)}]});let i={FunctionName:d.sub(`\${AWS::StackName}-${t.name}`),Runtime:t.runtime,Handler:t.handler,Role:d.getAtt(n,"Arn"),MemorySize:t.memory,Timeout:t.timeout,Code:{ZipFile:`exports.handler = async (event) => {
|
|
2484
2484
|
console.log('Event:', JSON.stringify(event, null, 2));
|
|
2485
2485
|
return { statusCode: 200, body: 'Function not yet implemented' };
|
|
2486
|
-
};`},Environment:t.environment?{Variables:t.environment}:void 0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}`)}]};if(a!=="edge")i.VpcConfig={SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],SecurityGroupIds:[d.ref("AppSecurityGroup")]};if(e.addResource(r,"AWS::Lambda::Function",i,{dependsOn:n}),e.addResource(`${r}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:d.sub(`/aws/lambda/\${AWS::StackName}-${t.name}`),RetentionInDays:14}),t.events)t.events.forEach((s,o)=>{
|
|
2486
|
+
};`},Environment:t.environment?{Variables:t.environment}:void 0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}`)}]};if(a!=="edge")i.VpcConfig={SubnetIds:[d.ref("PrivateSubnet1"),d.ref("PrivateSubnet2")],SecurityGroupIds:[d.ref("AppSecurityGroup")]};if(e.addResource(r,"AWS::Lambda::Function",i,{dependsOn:n}),e.addResource(`${r}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:d.sub(`/aws/lambda/\${AWS::StackName}-${t.name}`),RetentionInDays:14}),t.events)t.events.forEach((s,o)=>{Yi(e,r,s,o)});e.addOutputs({[`${r}Arn`]:{Description:`${t.name} function ARN`,Value:d.getAtt(r,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-function-arn`)}}})}function Yi(e,t,a,r){let n=`${t}EventSource${r}`;switch(a.type){case"http":break;case"s3":if(a.bucket){let i=e.toLogicalId(`${a.bucket}-bucket`);e.addResource(`${n}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(t),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:bt.s3Bucket(d.ref(i))},{dependsOn:[t,i]})}break;case"sqs":if(a.queueName){let i=e.toLogicalId(`${a.queueName}-queue`);e.addResource(n,"AWS::Lambda::EventSourceMapping",{EventSourceArn:d.getAtt(i,"Arn"),FunctionName:d.ref(t),BatchSize:a.batchSize||10},{dependsOn:[t,i]})}break;case"kinesis":if(a.streamName){let i=e.toLogicalId(`${a.streamName}-stream`);e.addResource(n,"AWS::Lambda::EventSourceMapping",{EventSourceArn:d.getAtt(i,"Arn"),FunctionName:d.ref(t),BatchSize:a.batchSize||100,StartingPosition:a.startingPosition||"LATEST",ParallelizationFactor:a.parallelizationFactor||1},{dependsOn:[t,i]})}break;case"dynamodb-stream":if(a.tableName){let i=e.toLogicalId(`${a.tableName}-table`);e.addResource(n,"AWS::Lambda::EventSourceMapping",{EventSourceArn:d.getAtt(i,"StreamArn"),FunctionName:d.ref(t),BatchSize:a.batchSize||100,StartingPosition:a.startingPosition||"LATEST"},{dependsOn:[t,i]})}break;case"schedule":if(a.expression)e.addResource(`${n}Rule`,"AWS::Events::Rule",{ScheduleExpression:a.expression,State:"ENABLED",Targets:[{Arn:d.getAtt(t,"Arn"),Id:`${t}Target`}]},{dependsOn:t}),e.addResource(`${n}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(t),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:d.getAtt(`${n}Rule`,"Arn")},{dependsOn:[t,`${n}Rule`]});break}}function Zi(e){let t=[];if(!e)return t;if(e.forEach((a)=>{switch(a.type){case"s3":t.push({Effect:"Allow",Action:["s3:GetObject","s3:GetObjectVersion"],Resource:a.bucket?`arn:aws:s3:::${a.bucket}/*`:"arn:aws:s3:::*/*"});break;case"sqs":t.push({Effect:"Allow",Action:["sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes"],Resource:a.queueName?bt.sqs(a.queueName):"arn:aws:sqs:*:*:*"});break;case"kinesis":t.push({Effect:"Allow",Action:["kinesis:GetRecords","kinesis:GetShardIterator","kinesis:DescribeStream","kinesis:ListStreams"],Resource:a.streamName?bt.kinesis(a.streamName):"arn:aws:kinesis:*:*:stream/*"});break;case"dynamodb-stream":t.push({Effect:"Allow",Action:["dynamodb:GetRecords","dynamodb:GetShardIterator","dynamodb:DescribeStream","dynamodb:ListStreams"],Resource:a.tableName?d.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${a.tableName}/stream/*`):"arn:aws:dynamodb:*:*:table/*/stream/*"});break}}),t.length===0)t.push({Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:*"});return t}function Xi(e,t){if(t.topics)t.topics.forEach((a)=>{es(e,a)})}function es(e,t){let a=e.toLogicalId(`${t.name}-topic`);if(e.addResource(a,"AWS::SNS::Topic",{TopicName:d.sub(`\${AWS::StackName}-${t.name}`),DisplayName:t.displayName||t.name,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t.name}`)}]}),e.addResource(`${a}Policy`,"AWS::SNS::TopicPolicy",{Topics:[d.ref(a)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["events.amazonaws.com","cloudwatch.amazonaws.com","s3.amazonaws.com"]},Action:"sns:Publish",Resource:d.ref(a)},{Effect:"Allow",Principal:{AWS:d.sub("arn:aws:iam::${AWS::AccountId}:root")},Action:["sns:Subscribe","sns:Publish","sns:Receive"],Resource:d.ref(a)}]}},{dependsOn:a}),t.subscriptions)t.subscriptions.forEach((r,n)=>{let i=`${a}Subscription${n+1}`,s={Protocol:r.protocol,TopicArn:d.ref(a),Endpoint:r.endpoint};if(r.filterPolicy)s.FilterPolicy=r.filterPolicy;if(r.protocol==="sqs"){let o=e.toLogicalId(`${r.endpoint}-queue`);s.Endpoint=d.getAtt(o,"Arn")}if(r.protocol==="lambda"){let o=e.toLogicalId(r.endpoint);s.Endpoint=d.getAtt(o,"Arn"),e.addResource(`${i}Permission`,"AWS::Lambda::Permission",{FunctionName:d.ref(o),Action:"lambda:InvokeFunction",Principal:"sns.amazonaws.com",SourceArn:d.ref(a)},{dependsOn:[o,a]})}e.addResource(i,"AWS::SNS::Subscription",s,{dependsOn:a})});e.addOutputs({[`${a}Arn`]:{Description:`${t.name} topic ARN`,Value:d.ref(a),Export:{Name:d.sub(`\${AWS::StackName}-${t.name}-topic-arn`)}}})}function ts(e,t){if(t.alarms&&t.alarms.length>0)e.addResource("AlarmTopic","AWS::SNS::Topic",{TopicName:d.sub("${AWS::StackName}-alarms"),DisplayName:"CloudWatch Alarms",Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-alarms")}]}),t.alarms.forEach((a,r)=>{as(e,a,r)});if(t.dashboard)rs(e,t.dashboard);if(t.logs?.groups)t.logs.groups.forEach((a)=>{ns(e,a,t.logs?.retention)})}function as(e,t,a){let r=e.toLogicalId(`alarm-${t.name||t.metric}-${a}`),n={AlarmName:t.name||d.sub(`\${AWS::StackName}-${t.metric}`),AlarmDescription:`Alarm for ${t.metric}`,MetricName:t.metric,Namespace:t.namespace||Vt(t.metric,t.service),Statistic:t.statistic||"Average",Period:t.period||300,EvaluationPeriods:t.evaluationPeriods||1,Threshold:t.threshold,ComparisonOperator:t.comparisonOperator||"GreaterThanThreshold",TreatMissingData:t.treatMissingData||"notBreaching",AlarmActions:[d.ref("AlarmTopic")],OKActions:[d.ref("AlarmTopic")]};if(t.dimensions)n.Dimensions=Object.entries(t.dimensions).map(([i,s])=>({Name:i,Value:s}));else if(t.service)n.Dimensions=is(t.service);e.addResource(r,"AWS::CloudWatch::Alarm",n,{dependsOn:"AlarmTopic"})}function rs(e,t){if(!t)return;let a=[],r=0,n=0;t.widgets?.forEach((i)=>{let s=i.width||12,o=i.height||6;if(i.type==="metric"&&i.metrics){let c=i.metrics.map((l)=>{if(typeof l==="string")return[Vt(l),l];else return[Vt(l.metric,l.service),l.metric]});a.push({type:"metric",x:r,y:n,width:s,height:o,properties:{metrics:c,period:300,stat:"Average",region:d.ref("AWS::Region"),title:i.metrics.length>1?"Multiple Metrics":typeof i.metrics[0]==="string"?i.metrics[0]:i.metrics[0].metric}})}else if(i.type==="log"&&i.logGroup)a.push({type:"log",x:r,y:n,width:s,height:o,properties:{query:`SOURCE '${i.logGroup}'
|
|
2487
2487
|
| fields @timestamp, @message
|
|
2488
2488
|
| sort @timestamp desc
|
|
2489
|
-
| limit 20`,region:d.ref("AWS::Region"),title:`Logs: ${i.logGroup}`}});else if(i.type==="text"&&i.text)a.push({type:"text",x:r,y:n,width:s,height:o,properties:{markdown:i.text}});if(r+=s,r>=24)r=0,n+=o}),e.addResource("CloudWatchDashboard","AWS::CloudWatch::Dashboard",{DashboardName:d.sub(`\${AWS::StackName}-${t.name}`),DashboardBody:JSON.stringify({widgets:a})}),e.addOutputs({DashboardURL:{Description:"CloudWatch Dashboard URL",Value:d.sub("https://console.aws.amazon.com/cloudwatch/home?region=${AWS::Region}#dashboards:name=${CloudWatchDashboard}")}})}function rs(e,t,a){let r=e.toLogicalId(`${t}-log-group`);e.addResource(r,"AWS::Logs::LogGroup",{LogGroupName:d.sub(`/aws/\${AWS::StackName}/${t}`),RetentionInDays:a||14,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]})}function Vt(e,t){if(t)return{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",dynamodb:"AWS/DynamoDB",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apigateway:"AWS/ApiGateway",sqs:"AWS/SQS",sns:"AWS/SNS",kinesis:"AWS/Kinesis",elasticache:"AWS/ElastiCache"}[t.toLowerCase()]||"AWS/CloudWatch";let a=e.toLowerCase();if(a.includes("cpu")||a.includes("memory")||a.includes("network"))return"AWS/EC2";if(a.includes("lambda")||a.includes("invocation")||a.includes("duration"))return"AWS/Lambda";if(a.includes("request")||a.includes("latency")||a.includes("target"))return"AWS/ApplicationELB";if(a.includes("database")||a.includes("connection"))return"AWS/RDS";if(a.includes("read")||a.includes("write")||a.includes("consumed"))return"AWS/DynamoDB";return"AWS/CloudWatch"}function ns(e){return{ec2:[{Name:"InstanceId",Value:d.ref("EC2Instance")}],ecs:[{Name:"ClusterName",Value:d.ref("ECSCluster")},{Name:"ServiceName",Value:d.getAtt("ECSService","Name")}],lambda:[{Name:"FunctionName",Value:d.ref("LambdaFunction")}],rds:[{Name:"DBInstanceIdentifier",Value:d.ref("Database")}],dynamodb:[{Name:"TableName",Value:d.ref("DynamoDBTable")}],alb:[{Name:"LoadBalancer",Value:d.getAtt("LoadBalancer","LoadBalancerFullName")}],apigateway:[{Name:"ApiName",Value:d.ref("HttpApi")}]}[e.toLowerCase()]||[]}function is(e,t){if(!t.vpc)return;let{cidr:a="10.0.0.0/16",availabilityZones:r=2,natGateways:n=1,enableDnsHostnames:i=!0,enableDnsSupport:s=!0}=t.vpc;e.addResource("VPC","AWS::EC2::VPC",{CidrBlock:a,EnableDnsHostnames:i,EnableDnsSupport:s,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-vpc")}]}),e.addResource("InternetGateway","AWS::EC2::InternetGateway",{Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-igw")}]}),e.addResource("VPCGatewayAttachment","AWS::EC2::VPCGatewayAttachment",{VpcId:d.ref("VPC"),InternetGatewayId:d.ref("InternetGateway")},{dependsOn:["VPC","InternetGateway"]});let o=[];for(let m=0;m<r;m++){let p=`PublicSubnet${m+1}`;o.push(p),e.addResource(p,"AWS::EC2::Subnet",{VpcId:d.ref("VPC"),CidrBlock:d.select(m,d.cidr(d.getAtt("VPC","CidrBlock"),r*2,8)),AvailabilityZone:d.select(m,d.getAZs()),MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-public-${m+1}`)},{Key:"Type",Value:"public"}]},{dependsOn:"VPC"})}let c=[];for(let m=0;m<r;m++){let p=`PrivateSubnet${m+1}`;c.push(p),e.addResource(p,"AWS::EC2::Subnet",{VpcId:d.ref("VPC"),CidrBlock:d.select(m+r,d.cidr(d.getAtt("VPC","CidrBlock"),r*2,8)),AvailabilityZone:d.select(m,d.getAZs()),MapPublicIpOnLaunch:!1,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-private-${m+1}`)},{Key:"Type",Value:"private"}]},{dependsOn:"VPC"})}let l=[];for(let m=0;m<n;m++){let p=`NatEIP${m+1}`;l.push(p),e.addResource(p,"AWS::EC2::EIP",{Domain:"vpc",Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-nat-eip-${m+1}`)}]},{dependsOn:"VPCGatewayAttachment"})}let u=[];for(let m=0;m<n;m++){let p=`NatGateway${m+1}`;u.push(p);let g=m%r;e.addResource(p,"AWS::EC2::NatGateway",{AllocationId:d.getAtt(l[m],"AllocationId"),SubnetId:d.ref(o[g]),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-nat-${m+1}`)}]},{dependsOn:[l[m],o[g]]})}e.addResource("PublicRouteTable","AWS::EC2::RouteTable",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-public-rt")}]},{dependsOn:"VPC"}),e.addResource("PublicRoute","AWS::EC2::Route",{RouteTableId:d.ref("PublicRouteTable"),DestinationCidrBlock:"0.0.0.0/0",GatewayId:d.ref("InternetGateway")},{dependsOn:["PublicRouteTable","VPCGatewayAttachment"]}),o.forEach((m,p)=>{e.addResource(`PublicSubnetRouteTableAssociation${p+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:d.ref(m),RouteTableId:d.ref("PublicRouteTable")},{dependsOn:[m,"PublicRouteTable"]})}),c.forEach((m,p)=>{let g=`PrivateRouteTable${p+1}`,h=p%n;e.addResource(g,"AWS::EC2::RouteTable",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-private-rt-${p+1}`)}]},{dependsOn:"VPC"}),e.addResource(`PrivateRoute${p+1}`,"AWS::EC2::Route",{RouteTableId:d.ref(g),DestinationCidrBlock:"0.0.0.0/0",NatGatewayId:d.ref(u[h])},{dependsOn:[g,u[h]]}),e.addResource(`PrivateSubnetRouteTableAssociation${p+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:d.ref(m),RouteTableId:d.ref(g)},{dependsOn:[m,g]})}),e.addResource("S3VPCEndpoint","AWS::EC2::VPCEndpoint",{VpcId:d.ref("VPC"),ServiceName:d.sub("com.amazonaws.${AWS::Region}.s3"),VpcEndpointType:"Gateway",RouteTableIds:[d.ref("PublicRouteTable"),...Array.from({length:r},(m,p)=>d.ref(`PrivateRouteTable${p+1}`))]},{dependsOn:"VPC"}),e.addResource("NetworkAcl","AWS::EC2::NetworkAcl",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-nacl")}]},{dependsOn:"VPC"}),e.addResource("NetworkAclEntryInbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:d.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),e.addResource("NetworkAclEntryOutbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:d.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,Egress:!0,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),e.addOutputs({VPCId:{Description:"VPC ID",Value:d.ref("VPC"),Export:{Name:d.sub("${AWS::StackName}-VPC")}},PublicSubnets:{Description:"Public subnet IDs",Value:d.join(",",o.map((m)=>d.ref(m))),Export:{Name:d.sub("${AWS::StackName}-PublicSubnets")}},PrivateSubnets:{Description:"Private subnet IDs",Value:d.join(",",c.map((m)=>d.ref(m))),Export:{Name:d.sub("${AWS::StackName}-PrivateSubnets")}}})}function ss(e,t){for(let[a,r]of Object.entries(t))os(e,a,r)}function os(e,t,a){let r=e.toLogicalId(`${t}-queue`),n=a.fifo||!1,i;if(a.deadLetterQueue){let o=`${r}DLQ`;e.addResource(o,"AWS::SQS::Queue",{QueueName:n?d.sub(`\${AWS::StackName}-${t}-dlq.fifo`):d.sub(`\${AWS::StackName}-${t}-dlq`),FifoQueue:n,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}-dlq`)}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),i=d.getAtt(o,"Arn")}let s={QueueName:n?d.sub(`\${AWS::StackName}-${t}.fifo`):d.sub(`\${AWS::StackName}-${t}`),FifoQueue:n,VisibilityTimeout:a.visibilityTimeout||30,MessageRetentionPeriod:a.messageRetentionPeriod||345600,ReceiveMessageWaitTimeSeconds:a.receiveMessageWaitTime||0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]};if(n&&a.contentBasedDeduplication)s.ContentBasedDeduplication=!0;if(a.deadLetterQueue&&i)s.RedrivePolicy={deadLetterTargetArn:i,maxReceiveCount:a.maxReceiveCount||3};if(e.addResource(r,"AWS::SQS::Queue",s,{dependsOn:a.deadLetterQueue?`${r}DLQ`:void 0,deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),e.addResource(`${r}Policy`,"AWS::SQS::QueuePolicy",{Queues:[d.ref(r)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","events.amazonaws.com","sns.amazonaws.com"]},Action:"sqs:SendMessage",Resource:d.getAtt(r,"Arn"),Condition:{ArnEquals:{"aws:SourceArn":d.sub("arn:aws:*:${AWS::Region}:${AWS::AccountId}:*")}}}]}},{dependsOn:r}),e.addOutputs({[`${r}Url`]:{Description:`${t} queue URL`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-queue-url`)}},[`${r}Arn`]:{Description:`${t} queue ARN`,Value:d.getAtt(r,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t}-queue-arn`)}}}),a.deadLetterQueue)e.addOutputs({[`${r}DLQUrl`]:{Description:`${t} dead letter queue URL`,Value:d.ref(`${r}DLQ`),Export:{Name:d.sub(`\${AWS::StackName}-${t}-dlq-url`)}}})}function cs(e,t){if(t.certificate)ls(e,t.certificate);if(t.waf?.enabled)us(e,t.waf);if(t.securityGroups)for(let[a,r]of Object.entries(t.securityGroups))ds(e,a,r)}function ls(e,t){if(!t)return;let a=[t.domain];if(t.subdomains)a.push(...t.subdomains);e.addResource("Certificate","AWS::CertificateManager::Certificate",{DomainName:t.domain,SubjectAlternativeNames:t.subdomains,ValidationMethod:t.validationMethod||"DNS",DomainValidationOptions:a.map((r)=>({DomainName:r,HostedZoneId:d.ref("HostedZone")})),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-certificate")}]}),e.addOutputs({CertificateArn:{Description:"ACM Certificate ARN",Value:d.ref("Certificate"),Export:{Name:d.sub("${AWS::StackName}-certificate-arn")}}})}function us(e,t){if(!t)return;let a=[],r=t.rules||["rateLimit","sqlInjection","xss"];if(r.includes("rateLimit"))a.push({Name:"RateLimitRule",Priority:1,Statement:{RateBasedStatement:{Limit:t.rateLimit||2000,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"RateLimitRule"}});let n=a.length+1;if(r.includes("sqlInjection"))a.push({Name:"AWSManagedRulesSQLi",Priority:n++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesSQLiRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesSQLi"}});if(r.includes("xss"))a.push({Name:"AWSManagedRulesXSS",Priority:n++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesXSS"}});if(r.includes("knownBadInputs"))a.push({Name:"AWSManagedRulesKnownBadInputs",Priority:n++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesKnownBadInputs"}});if(r.includes("coreRuleSet"))a.push({Name:"AWSManagedRulesCoreRuleSet",Priority:n++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesCommonRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesCoreRuleSet"}});if(r.includes("linuxRuleSet"))a.push({Name:"AWSManagedRulesLinuxRuleSet",Priority:n++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesLinuxRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesLinuxRuleSet"}});if(r.includes("apiProtection"))a.push({Name:"AWSManagedRulesAPIProtection",Priority:n++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesAmazonIpReputationList"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesAPIProtection"}});if(r.includes("geoBlock"))a.push({Name:"GeoBlockRule",Priority:n++,Statement:{GeoMatchStatement:{CountryCodes:["CN","RU"]}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"GeoBlockRule"}});if(r.includes("connectionLimit"))a.push({Name:"ConnectionLimitRule",Priority:n++,Statement:{RateBasedStatement:{Limit:100,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"ConnectionLimitRule"}});if(e.addResource("WebACL","AWS::WAFv2::WebACL",{Name:d.sub("${AWS::StackName}-waf"),Scope:t.scope||"REGIONAL",DefaultAction:{Allow:{}},Rules:a,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:d.sub("${AWS::StackName}-waf")},Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-waf")}]}),e.hasResource("LoadBalancer"))e.addResource("WebACLAssociation","AWS::WAFv2::WebACLAssociation",{ResourceArn:d.ref("LoadBalancer"),WebACLArn:d.getAtt("WebACL","Arn")},{dependsOn:["WebACL","LoadBalancer"]});e.addOutputs({WebACLId:{Description:"WAF Web ACL ID",Value:d.ref("WebACL"),Export:{Name:d.sub("${AWS::StackName}-waf-id")}},WebACLArn:{Description:"WAF Web ACL ARN",Value:d.getAtt("WebACL","Arn"),Export:{Name:d.sub("${AWS::StackName}-waf-arn")}}})}function ds(e,t,a){if(!a)return;let r=e.toLogicalId(`${t}-security-group`),n=a.ingress?.map((s)=>({IpProtocol:s.protocol,FromPort:s.port,ToPort:s.port,CidrIp:s.cidr,SourceSecurityGroupId:s.source?d.ref(s.source):void 0}))||[],i=a.egress?.map((s)=>({IpProtocol:s.protocol,FromPort:s.port,ToPort:s.port,CidrIp:s.cidr||"0.0.0.0/0"}))||[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}];e.addResource(r,"AWS::EC2::SecurityGroup",{GroupDescription:`Security group for ${t}`,VpcId:d.ref("VPC"),SecurityGroupIngress:n,SecurityGroupEgress:i,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}-sg`)}]},{dependsOn:"VPC"}),e.addOutputs({[`${r}Id`]:{Description:`${t} security group ID`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-sg-id`)}}})}function ms(e,t){for(let[a,r]of Object.entries(t)){if(r.type==="efs"){gs(e,a,r);continue}ps(e,a,r)}}function ps(e,t,a){let r=e.toLogicalId(`${t}-bucket`),n={BucketName:d.sub(`\${AWS::StackName}-${t}`),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]};if(a.versioning)n.VersioningConfiguration={Status:"Enabled"};if(a.encryption)n.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(!a.public)n.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(a.website)n.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"index.html"};if(a.cors&&a.cors.length>0)n.CorsConfiguration={CorsRules:a.cors.map((i)=>({AllowedOrigins:i.allowedOrigins,AllowedMethods:i.allowedMethods,AllowedHeaders:i.allowedHeaders||["*"],MaxAge:i.maxAge||3600}))};if(a.lifecycleRules&&a.lifecycleRules.length>0)n.LifecycleConfiguration={Rules:a.lifecycleRules.map((i)=>({Id:i.id,Status:i.enabled?"Enabled":"Disabled",ExpirationInDays:i.expirationDays,Transitions:i.transitions?.map((s)=>({TransitionInDays:s.days,StorageClass:s.storageClass}))}))};if(a.intelligentTiering)n.IntelligentTieringConfigurations=[{Id:"EntireBucket",Status:"Enabled",Tierings:[{AccessTier:"ARCHIVE_ACCESS",Days:90},{AccessTier:"DEEP_ARCHIVE_ACCESS",Days:180}]}];if(e.addResource(r,"AWS::S3::Bucket",n,{deletionPolicy:a.versioning?"Retain":"Delete"}),a.public)e.addResource(`${r}Policy`,"AWS::S3::BucketPolicy",{Bucket:d.ref(r),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:"s3:GetObject",Resource:d.join("",[St.s3Bucket(d.ref(r)),"/*"])}]}},{dependsOn:r});if(e.addOutputs({[`${r}Name`]:{Description:`${t} bucket name`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-bucket`)}},[`${r}Arn`]:{Description:`${t} bucket ARN`,Value:d.getAtt(r,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t}-bucket-arn`)}}}),a.website)e.addOutputs({[`${r}WebsiteURL`]:{Description:`${t} website URL`,Value:d.getAtt(r,"WebsiteURL")}})}function gs(e,t,a){let r=e.toLogicalId(`${t}-efs`),n={Encrypted:a.encryption!==!1,PerformanceMode:a.performanceMode||"generalPurpose",ThroughputMode:a.throughputMode||"bursting",FileSystemTags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]};if(a.lifecyclePolicy){if(n.LifecyclePolicies=[],a.lifecyclePolicy.transitionToIA)n.LifecyclePolicies.push({TransitionToIA:`AFTER_${a.lifecyclePolicy.transitionToIA}_DAYS`});if(a.lifecyclePolicy.transitionToPrimaryStorageClass)n.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"})}e.addResource(r,"AWS::EFS::FileSystem",n,{deletionPolicy:"Retain"});let i=2;for(let s=0;s<i;s++)e.addResource(`${r}MountTarget${s+1}`,"AWS::EFS::MountTarget",{FileSystemId:d.ref(r),SubnetId:d.ref(`PrivateSubnet${s+1}`),SecurityGroups:[d.ref("EFSSecurityGroup")]},{dependsOn:[r,`PrivateSubnet${s+1}`]});e.addResource("EFSSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for EFS mount targets",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-efs-sg")}]},{dependsOn:"VPC"}),e.addOutputs({[`${r}Id`]:{Description:`${t} EFS file system ID`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-efs`)}}})}class qa{template;config;resourceDependencies;constructor(e){this.config=e,this.resourceDependencies=new Map,this.template={AWSTemplateFormatVersion:"2010-09-09",Description:`Infrastructure for ${e.project.name} (${e.project.slug})`,Resources:{}}}build(){return this.addParameters(),this.addMappings(),this.addConditions(),this.addResources(),this.initializeOutputs(),this.resolveDependencies(),this.template}addParameters(){this.template.Parameters={Environment:{Type:"String",Default:"production",AllowedValues:["development","staging","production"],Description:"Environment name"}}}addMappings(){this.template.Mappings={RegionMap:{"us-east-1":{AMI:"ami-0f3caa1cf4417e51b"},"us-west-2":{AMI:"ami-0d1cd67c26f5fca19"},"eu-west-1":{AMI:"ami-0bbc25e23a7640b9b"}}}}addConditions(){this.template.Conditions={IsProduction:d.equals(d.ref("Environment"),"production"),HasDomain:d.not([d.equals(this.config.environments?.production?.domain||"","")])}}addResources(){let{infrastructure:e}=this.config;if(!e)return;if(e.network)this.addNetworkResources(e.network);if(e.storage)this.addStorageResources(e.storage);if(e.compute)this.addComputeResources(e.compute);if(e.databases)this.addDatabaseResources(e.databases);if(e.cache)this.addCacheResources(e.cache);if(e.cdn)this.addCDNResources(e.cdn);if(e.apiGateway)this.addApiGatewayResources(e.apiGateway);if(e.functions)this.addFunctionResources(e.functions);if(e.queues)this.addQueueResources(e.queues);if(e.messaging)this.addMessagingResources(e.messaging);if(e.monitoring)this.addMonitoringResources(e.monitoring);if(e.security)this.addSecurityResources(e.security)}initializeOutputs(){let e=this.template.Outputs||{};if(this.template.Outputs={StackName:{Description:"Stack name",Value:d.ref("AWS::StackName"),Export:{Name:d.sub("${AWS::StackName}-Name")}},Region:{Description:"AWS Region",Value:d.ref("AWS::Region"),Export:{Name:d.sub("${AWS::StackName}-Region")}},...e},this.config.environments?.production?.domain)this.template.Outputs.Domain={Description:"Production domain",Value:this.config.environments.production.domain,Condition:"HasDomain"}}addResource(e,t,a,r){let n={Type:t,Properties:a};if(r?.dependsOn)n.DependsOn=r.dependsOn,this.trackDependency(e,r.dependsOn);if(r?.condition)n.Condition=r.condition;if(r?.deletionPolicy)n.DeletionPolicy=r.deletionPolicy;if(r?.updateReplacePolicy)n.UpdateReplacePolicy=r.updateReplacePolicy;this.template.Resources[e]=n}addOutputs(e){this.template.Outputs={...this.template.Outputs,...e}}getOutputs(){return this.template.Outputs||{}}hasResource(e){return e in this.template.Resources}getResource(e){return this.template.Resources[e]}trackDependency(e,t){if(!this.resourceDependencies.has(e))this.resourceDependencies.set(e,new Set);(Array.isArray(t)?t:[t]).forEach((a)=>this.resourceDependencies.get(e).add(a))}resolveDependencies(){let e=new Set,t=new Set,a=(r)=>{if(t.has(r))throw Error(`Circular dependency detected involving resource: ${r}`);if(e.has(r))return!0;e.add(r),t.add(r);let n=this.resourceDependencies.get(r);if(n)for(let i of n)a(i);return t.delete(r),!0};for(let r of this.resourceDependencies.keys())a(r)}toLogicalId(e){return e.split(/[-_\s]/).map((t)=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}addNetworkResources(e){is(this,e)}addStorageResources(e){ms(this,e)}addComputeResources(e){ji(this,e)}addDatabaseResources(e){qi(this,e)}addFunctionResources(e){Ji(this,e)}addCacheResources(e){_i(this,e)}addQueueResources(e){ss(this,e)}addMessagingResources(e){Xi(this,e)}addCDNResources(e){Vi(this,e)}addApiGatewayResources(e){ki(this,e)}addMonitoringResources(e){es(this,e)}addSecurityResources(e){cs(this,e)}}function El(e){return new qa(e).build()}function Pl(e){let{name:t,slug:a,domain:r,subdomain:n}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:n&&r?`${n}.${r}`:r}},infrastructure:{storage:{assets:{public:!0,versioning:!1,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"],allowedHeaders:["*"],maxAge:3600}]}},cdn:{enabled:!0,customDomain:r?{domain:n&&r?`${n}.${r}`:r,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0,errorPages:{404:"/index.html",403:"/index.html"}}}}}function Il(e){let{name:t,slug:a,domain:r,instanceType:n="t3.small",minInstances:i=2,maxInstances:s=10}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:n,ami:"ubuntu-22.04",keyPair:`${a}-key`,autoScaling:{min:i,max:s,desired:i,targetCPU:70},loadBalancer:{type:"application",healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3}},userData:{packages:["nodejs","npm","nginx"],commands:["curl -fsSL https://bun.sh/install | bash","npm install -g pm2"]}}},databases:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.micro",allocatedStorage:20,multiAZ:!0,backupRetentionDays:7,deletionProtection:!0}},cache:{redis:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},security:{certificate:r?{domain:r,subdomains:[`*.${r}`],validationMethod:"DNS"}:void 0}}}}function Rl(e){let{name:t,slug:a,domain:r,taskCpu:n="256",taskMemory:i="512",desiredCount:s=2}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:0}},compute:{fargate:{taskDefinition:{cpu:n,memory:i,containerDefinitions:[{name:"app",image:`${a}-app:latest`,portMappings:[{containerPort:3000}],environment:[],secrets:[]}]},service:{desiredCount:s,healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},autoScaling:{min:s,max:s*5,targetCPU:70,targetMemory:80}},loadBalancer:{type:"application"}}},databases:{dynamodb:{tables:{[`${a}-main`]:{partitionKey:{name:"id",type:"S"},sortKey:{name:"createdAt",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0}}}},functions:{"process-queue":{runtime:"nodejs20.x",handler:"dist/workers/queue.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${a}-queue`}]}},security:{certificate:r?{domain:r,subdomains:[`*.${r}`],validationMethod:"DNS"}:void 0}}}}function Nl(e){let{name:t,slug:a,entry:r,domain:n,runtime:i="nodejs20.x",memory:s=1024,build:o,deploy:c,assets:l,queues:u=!0,scheduler:m="on",region:p="us-east-1"}=e;return{project:{name:t,slug:a,region:p},mode:"serverless",environments:{production:{type:"production",domain:n,app:{kind:"node",runtime:i,entry:r,memory:s,build:o,deploy:c,assets:l,queues:u,scheduler:m,domain:n}}}}}function Dl(e){let t=e.database!==!1,a=e.cache!==!1,r=e.queue!==!1;return{project:{name:e.name,slug:e.slug,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:e.domain}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{fargate:{taskDefinition:{cpu:"256",memory:"512",containerDefinitions:[{name:"api",image:e.imageUri,portMappings:[{containerPort:3000}],environment:[{name:"NODE_ENV",value:"production"},{name:"PORT",value:"3000"},{name:"AWS_REGION",value:d.ref("AWS::Region")},...t?[{name:"DB_HOST",value:d.getAtt("PostgresDb","Endpoint.Address")},{name:"DB_PORT",value:d.getAtt("PostgresDb","Endpoint.Port")}]:[],...a?[{name:"REDIS_HOST",value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address")},{name:"REDIS_PORT",value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port")},{name:"REDIS_TLS",value:"true"}]:[],...r?[{name:"QUEUE_URL",value:d.ref("JobsQueue")}]:[],{name:"MAIL_TRANSPORT",value:"ses"}],secrets:t?[{name:"DB_USERNAME",valueFrom:d.sub("${DBSecret}:username::")},{name:"DB_PASSWORD",valueFrom:d.sub("${DBSecret}:password::")}]:[]}]},service:{desiredCount:e.desiredCount||1,healthCheck:{path:"/api/health",interval:30,timeout:5},autoScaling:{min:e.desiredCount||1,max:6,targetCPU:70}},loadBalancer:{type:"application",...e.certificateArn?{customDomain:{domain:e.domain,certificateArn:e.certificateArn}}:{},...e.originVerifySecret?{originVerifyHeader:{name:"X-Origin-Verify",value:e.originVerifySecret}}:{}}}},...t?{databases:{postgres:{engine:"postgres",version:"16",instanceClass:"db.t4g.micro",allocatedStorage:20,maxAllocatedStorage:100,multiAZ:!1,backupRetentionDays:7,deletionProtection:!0}}}:{},...a?{cache:{redis:{nodeType:"cache.t4g.micro",numCacheNodes:2,engine:"redis",engineVersion:"7.1",automaticFailoverEnabled:!0,snapshotRetentionLimit:5}}}:{},...r?{queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0,maxReceiveCount:3,receiveMessageWaitTime:20}}}:{}}}}function kl(e){let{name:t,slug:a,domain:r,apiSubdomain:n="api"}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},storage:{frontend:{public:!0,versioning:!0,website:!0,encryption:!1}},cdn:{enabled:!0,customDomain:{domain:r,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0,errorPages:{404:"/index.html"}},compute:{fargate:{taskDefinition:{cpu:"512",memory:"1024",containerDefinitions:[{name:"api",image:`${a}-api:latest`,portMappings:[{containerPort:3000}]}]},service:{desiredCount:2,healthCheck:{path:"/api/health",interval:30},autoScaling:{min:2,max:10,targetCPU:70}},loadBalancer:{type:"application",customDomain:{domain:`${n}.${r}`,certificateArn:"TO_BE_GENERATED"}}}},databases:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.small",allocatedStorage:50,multiAZ:!0,backupRetentionDays:14,deletionProtection:!0}},cache:{redis:{nodeType:"cache.t3.small",numCacheNodes:2,engine:"redis",engineVersion:"7.0"}},queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0}},security:{certificate:{domain:r,subdomains:[`*.${r}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss"]}}}}}function Ml(e){let{name:t,slug:a,domain:r}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{apiGateway:{type:"HTTP",cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"],allowHeaders:["Content-Type","Authorization"],maxAge:3600},customDomain:r?{domain:r,certificateArn:"TO_BE_GENERATED"}:void 0,throttling:{rateLimit:1e4,burstLimit:5000},authorizer:{type:"JWT",identitySource:"$request.header.Authorization"}},functions:{users:{runtime:"nodejs20.x",handler:"dist/api/users.handler",memory:512,timeout:30,events:[{type:"http",path:"/users",method:"GET"},{type:"http",path:"/users",method:"POST"}]},products:{runtime:"nodejs20.x",handler:"dist/api/products.handler",memory:512,timeout:30,events:[{type:"http",path:"/products",method:"GET"}]}},databases:{dynamodb:{tables:{[`${a}-users`]:{partitionKey:{name:"userId",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"EmailIndex",partitionKey:{name:"email",type:"S"},projection:"ALL"}]},[`${a}-products`]:{partitionKey:{name:"productId",type:"S"},sortKey:{name:"category",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!1}}}},cache:{elasticache:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},security:{certificate:r?{domain:r,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}},monitoring:{alarms:[{metric:"Errors",threshold:10,period:300,evaluationPeriods:1},{metric:"Duration",threshold:3000,period:300,evaluationPeriods:2}]}}}}function Ll(e){let{name:t,slug:a,domain:r,instanceType:n="t3.small"}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:n,ami:"ubuntu-22.04",keyPair:`${a}-key`,autoScaling:{min:2,max:6,desired:2,targetCPU:75},loadBalancer:{type:"application",healthCheck:{path:"/wp-admin/install.php",interval:30}},userData:{packages:["nginx","php8.1-fpm","php8.1-mysql","php8.1-curl","php8.1-gd","php8.1-mbstring","php8.1-xml","php8.1-zip"],commands:["cd /var/www","wget https://wordpress.org/latest.tar.gz","tar -xzf latest.tar.gz","chown -R www-data:www-data wordpress","rm /etc/nginx/sites-enabled/default","systemctl restart nginx","systemctl restart php8.1-fpm"]}}},fileSystem:{uploads:{performanceMode:"generalPurpose",throughputMode:"bursting",encrypted:!0,lifecyclePolicy:{transitionToIA:30},mountPath:"/var/www/wordpress/wp-content/uploads"}},databases:{mysql:{engine:"mysql",version:"8.0",instanceClass:"db.t3.small",allocatedStorage:50,multiAZ:!0,backupRetentionDays:7,deletionProtection:!0,databaseName:"wordpress"}},cache:{redis:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},cdn:{enabled:!0,customDomain:{domain:r,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,origins:[{type:"alb",pathPattern:"/wp-content/*"}]},security:{certificate:{domain:r,subdomains:[`www.${r}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","wordpressRules"]}}}}}function xl(e){let{name:t,slug:a,domain:r,apiDomain:n}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{storage:{static:{public:!0,versioning:!0,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"]}],lifecycleRules:[{id:"DeleteOldVersions",enabled:!0,expirationDays:90}]}},cdn:{enabled:!0,customDomain:{domain:r,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:0,maxTTL:31536000},compress:!0,http3:!0,errorPages:{404:"/404.html",500:"/500.html"},edgeFunctions:[{eventType:"origin-request",functionArn:"TO_BE_CREATED",name:"ssr-handler"}]},functions:{ssr:{runtime:"nodejs20.x",handler:"dist/edge/ssr.handler",memory:512,timeout:5},...n?{api:{runtime:"nodejs20.x",handler:"dist/api/index.handler",memory:1024,timeout:30,events:[{type:"http",path:"/{proxy+}",method:"ANY"}]}}:{}},apiGateway:n?{type:"HTTP",customDomain:{domain:n,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:[r],allowMethods:["GET","POST","PUT","DELETE"],allowHeaders:["Content-Type","Authorization"]}}:void 0,databases:{dynamodb:{tables:{content:{partitionKey:{name:"id",type:"S"},sortKey:{name:"type",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!1}}}},security:{certificate:{domain:r,subdomains:n?[n]:[],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","geoBlock"]}}}}}function Ol(e){let{name:t,slug:a,domain:r,services:n}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:3,natGateways:2}},compute:{services:n.map((i)=>({name:i.name,type:"fargate",taskDefinition:{cpu:i.cpu||"256",memory:i.memory||"512",containerDefinitions:[{name:i.name,image:`${a}-${i.name}:latest`,portMappings:[{containerPort:i.port}],healthCheck:{command:["CMD-SHELL",`curl -f http://localhost:${i.port}/health || exit 1`],interval:30,timeout:5,retries:3}}]},service:{desiredCount:i.desiredCount||2,serviceDiscovery:{enabled:!0,namespace:`${a}.local`},autoScaling:{min:2,max:10,targetCPU:70}}}))},apiGateway:{type:"HTTP",customDomain:{domain:r,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"]},routes:n.map((i)=>({path:`/${i.name}/{proxy+}`,integration:{type:"vpc-link",service:i.name}}))},databases:{dynamodb:{tables:Object.fromEntries(n.map((i)=>[`${a}-${i.name}`,{partitionKey:{name:"id",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0}]))}},queues:{events:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0}},messaging:{topics:{events:{name:`${a}-events`,subscriptions:n.map((i)=>({protocol:"sqs",endpoint:`${a}-${i.name}-queue`,filterPolicy:{service:[i.name]}}))}}},monitoring:{dashboard:{name:`${a}-microservices`,widgets:n.map((i)=>({type:"metric",metrics:[{service:i.name,metric:"CPUUtilization"},{service:i.name,metric:"MemoryUtilization"},{service:i.name,metric:"RequestCount"}]}))},alarms:n.flatMap((i)=>[{name:`${i.name}-high-cpu`,metric:"CPUUtilization",threshold:80,service:i.name},{name:`${i.name}-errors`,metric:"Errors",threshold:10,service:i.name}])},security:{certificate:{domain:r,validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}}}}}function Wl(e){let{name:t,slug:a,domain:r}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{apiGateway:{type:"websocket",customDomain:r?{domain:r,certificateArn:"TO_BE_GENERATED"}:void 0,routes:[{path:"$connect",method:"WEBSOCKET",integration:"websocket-connect"},{path:"$disconnect",method:"WEBSOCKET",integration:"websocket-disconnect"},{path:"$default",method:"WEBSOCKET",integration:"websocket-default"},{path:"sendMessage",method:"WEBSOCKET",integration:"websocket-send-message"},{path:"joinRoom",method:"WEBSOCKET",integration:"websocket-join-room"}]},functions:{connect:{runtime:"nodejs20.x",handler:"dist/websocket/connect.handler",memory:512,timeout:30},disconnect:{runtime:"nodejs20.x",handler:"dist/websocket/disconnect.handler",memory:512,timeout:30},default:{runtime:"nodejs20.x",handler:"dist/websocket/default.handler",memory:512,timeout:30},"send-message":{runtime:"nodejs20.x",handler:"dist/websocket/sendMessage.handler",memory:512,timeout:30},"join-room":{runtime:"nodejs20.x",handler:"dist/websocket/joinRoom.handler",memory:512,timeout:30},broadcast:{runtime:"nodejs20.x",handler:"dist/streams/broadcast.handler",memory:1024,timeout:60,events:[{type:"dynamodb-stream",tableName:`${a}-messages`,startingPosition:"LATEST",batchSize:100}]}},databases:{dynamodb:{tables:{[`${a}-connections`]:{partitionKey:{name:"connectionId",type:"S"},billingMode:"PAY_PER_REQUEST",globalSecondaryIndexes:[{name:"RoomIndex",partitionKey:{name:"roomId",type:"S"},sortKey:{name:"connectionId",type:"S"},projection:"ALL"}]},[`${a}-messages`]:{partitionKey:{name:"roomId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"UserIndex",partitionKey:{name:"userId",type:"S"},sortKey:{name:"timestamp",type:"S"},projection:"ALL"}]},[`${a}-rooms`]:{partitionKey:{name:"roomId",type:"S"},billingMode:"PAY_PER_REQUEST"}}}},cache:{elasticache:{nodeType:"cache.t3.small",numCacheNodes:2,engine:"redis",engineVersion:"7.0"}},monitoring:{alarms:[{metric:"WebSocketConnections",threshold:1e4,evaluationPeriods:1},{metric:"IntegrationLatency",threshold:1000,evaluationPeriods:2}],dashboard:{name:`${a}-realtime`,widgets:[{type:"metric",metrics:["WebSocketConnections","MessagesSent","IntegrationLatency"]}]}},security:{certificate:r?{domain:r,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","connectionLimit"]}}}}}function _l(e){let{name:t,slug:a,retentionDays:r=7}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",infrastructure:{streaming:{dataStream:{name:`${a}-stream`,shardCount:2,retentionPeriod:r*24,encryption:!0}},storage:{raw:{public:!1,versioning:!0,encryption:!0,intelligentTiering:!0,lifecycleRules:[{id:"ArchiveOldData",enabled:!0,transitions:[{days:30,storageClass:"GLACIER"},{days:90,storageClass:"DEEP_ARCHIVE"}]}]},processed:{public:!1,versioning:!0,encryption:!0,intelligentTiering:!0}},functions:{"stream-processor":{runtime:"nodejs20.x",handler:"dist/processors/stream.handler",memory:2048,timeout:300,events:[{type:"kinesis",streamName:`${a}-stream`,batchSize:1000,startingPosition:"LATEST",parallelizationFactor:10}]},transformer:{runtime:"nodejs20.x",handler:"dist/processors/transform.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${a}-raw`,prefix:"incoming/"}]},aggregator:{runtime:"nodejs20.x",handler:"dist/processors/aggregate.handler",memory:2048,timeout:600,events:[{type:"schedule",expression:"cron(0 * * * ? *)"}]}},analytics:{athena:{database:`${a}_analytics`,workgroup:`${a}-workgroup`,outputBucket:`${a}-query-results`,tables:[{name:"raw_events",location:`s3://${a}-raw/events/`,format:"parquet",partitionKeys:["year","month","day"]},{name:"processed_events",location:`s3://${a}-processed/events/`,format:"parquet",partitionKeys:["year","month","day"]}]},glue:{crawlers:[{name:`${a}-crawler`,databaseName:`${a}_analytics`,s3Targets:[`s3://${a}-raw/`,`s3://${a}-processed/`],schedule:"cron(0 2 * * ? *)"}],jobs:[{name:`${a}-etl-job`,scriptLocation:`s3://${a}-scripts/etl.py`,role:`${a}-glue-role`,maxCapacity:10,timeout:120}]}},databases:{dynamodb:{tables:{[`${a}-metadata`]:{partitionKey:{name:"pipelineId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST"}}}},queues:{failedJobs:{fifo:!1,visibilityTimeout:900,messageRetentionPeriod:1209600,deadLetterQueue:!0,maxReceiveCount:3}},workflow:{pipelines:[{name:`${a}-daily-pipeline`,type:"stepFunctions",definition:{StartAt:"ExtractData",States:{ExtractData:{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Next:"TransformData"},TransformData:{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Next:"LoadData"},LoadData:{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",End:!0}}},schedule:"cron(0 0 * * ? *)"}]},monitoring:{dashboard:{name:`${a}-pipeline`,widgets:[{type:"metric",metrics:["KinesisIncomingRecords","LambdaInvocations","S3ObjectsCreated","GlueJobsSucceeded"]}]},alarms:[{metric:"LambdaErrors",threshold:10,evaluationPeriods:1},{metric:"KinesisIteratorAge",threshold:60000,evaluationPeriods:2}]}}}}function Bl(e){let{name:t,slug:a,domain:r,modelS3Path:n=`s3://${a}-models/`,instanceType:i="ml.t3.medium"}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{storage:{models:{public:!1,versioning:!0,encryption:!0,intelligentTiering:!0},datasets:{public:!1,versioning:!0,encryption:!0,lifecycleRules:[{id:"ArchiveOldDatasets",enabled:!0,transitions:[{days:90,storageClass:"GLACIER"}]}]},predictions:{public:!1,versioning:!1,encryption:!0,lifecycleRules:[{id:"DeleteOldPredictions",enabled:!0,expirationDays:30}]}},machineLearning:{sagemaker:{endpoints:[{name:`${a}-inference`,modelS3Path:n,instanceType:i,initialInstanceCount:1,autoScaling:{minInstances:1,maxInstances:5,targetInvocationsPerInstance:1000}}],trainingJobs:[{name:`${a}-training`,algorithmSpecification:{trainingImage:"TO_BE_SPECIFIED",trainingInputMode:"File"},instanceType:"ml.p3.2xlarge",instanceCount:1,volumeSizeInGB:50,maxRuntimeInSeconds:86400}]}},apiGateway:{type:"HTTP",customDomain:r?{domain:r,certificateArn:"TO_BE_GENERATED"}:void 0,cors:{allowOrigins:["*"],allowMethods:["POST"],allowHeaders:["Content-Type","Authorization"]},throttling:{rateLimit:1000,burstLimit:500}},functions:{predict:{runtime:"python3.11",handler:"handlers/predict.handler",memory:2048,timeout:60,events:[{type:"http",path:"/predict",method:"POST"}],environment:{SAGEMAKER_ENDPOINT:`${a}-inference`,MODEL_BUCKET:`${a}-models`}},"batch-predict":{runtime:"python3.11",handler:"handlers/batchPredict.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${a}-datasets`,suffix:".csv"}]},"trigger-training":{runtime:"python3.11",handler:"handlers/training.handler",memory:1024,timeout:300,events:[{type:"schedule",expression:"cron(0 2 * * ? *)"}]}},databases:{dynamodb:{tables:{[`${a}-predictions`]:{partitionKey:{name:"requestId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0},[`${a}-models`]:{partitionKey:{name:"modelId",type:"S"},sortKey:{name:"version",type:"S"},billingMode:"PAY_PER_REQUEST"}}}},queues:{predictions:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:86400,deadLetterQueue:!0}},monitoring:{dashboard:{name:`${a}-ml`,widgets:[{type:"metric",metrics:["SageMakerInvocations","SageMakerModelLatency","APIGatewayRequests","LambdaErrors"]}]},alarms:[{metric:"SageMakerModelLatency",threshold:1000,evaluationPeriods:2},{metric:"SageMakerInvocationErrors",threshold:10,evaluationPeriods:1}]},security:{certificate:r?{domain:r,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","apiProtection"]}}}}}function Ul(e){let{name:t,slug:a,domain:r,instanceType:n="t3.medium",minInstances:i=2,maxInstances:s=10,databaseEngine:o="mysql",sessionStore:c="redis"}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:2}},compute:{server:{instanceType:n,ami:"ubuntu-22.04",autoScaling:{min:i,max:s,targetCPU:70,scaleUpCooldown:300,scaleDownCooldown:300},loadBalancer:{type:"application",healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},stickySession:{enabled:!0,duration:86400}},userData:`#!/bin/bash
|
|
2489
|
+
| limit 20`,region:d.ref("AWS::Region"),title:`Logs: ${i.logGroup}`}});else if(i.type==="text"&&i.text)a.push({type:"text",x:r,y:n,width:s,height:o,properties:{markdown:i.text}});if(r+=s,r>=24)r=0,n+=o}),e.addResource("CloudWatchDashboard","AWS::CloudWatch::Dashboard",{DashboardName:d.sub(`\${AWS::StackName}-${t.name}`),DashboardBody:JSON.stringify({widgets:a})}),e.addOutputs({DashboardURL:{Description:"CloudWatch Dashboard URL",Value:d.sub("https://console.aws.amazon.com/cloudwatch/home?region=${AWS::Region}#dashboards:name=${CloudWatchDashboard}")}})}function ns(e,t,a){let r=e.toLogicalId(`${t}-log-group`);e.addResource(r,"AWS::Logs::LogGroup",{LogGroupName:d.sub(`/aws/\${AWS::StackName}/${t}`),RetentionInDays:a||14,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]})}function Vt(e,t){if(t)return{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",dynamodb:"AWS/DynamoDB",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apigateway:"AWS/ApiGateway",sqs:"AWS/SQS",sns:"AWS/SNS",kinesis:"AWS/Kinesis",elasticache:"AWS/ElastiCache"}[t.toLowerCase()]||"AWS/CloudWatch";let a=e.toLowerCase();if(a.includes("cpu")||a.includes("memory")||a.includes("network"))return"AWS/EC2";if(a.includes("lambda")||a.includes("invocation")||a.includes("duration"))return"AWS/Lambda";if(a.includes("request")||a.includes("latency")||a.includes("target"))return"AWS/ApplicationELB";if(a.includes("database")||a.includes("connection"))return"AWS/RDS";if(a.includes("read")||a.includes("write")||a.includes("consumed"))return"AWS/DynamoDB";return"AWS/CloudWatch"}function is(e){return{ec2:[{Name:"InstanceId",Value:d.ref("EC2Instance")}],ecs:[{Name:"ClusterName",Value:d.ref("ECSCluster")},{Name:"ServiceName",Value:d.getAtt("ECSService","Name")}],lambda:[{Name:"FunctionName",Value:d.ref("LambdaFunction")}],rds:[{Name:"DBInstanceIdentifier",Value:d.ref("Database")}],dynamodb:[{Name:"TableName",Value:d.ref("DynamoDBTable")}],alb:[{Name:"LoadBalancer",Value:d.getAtt("LoadBalancer","LoadBalancerFullName")}],apigateway:[{Name:"ApiName",Value:d.ref("HttpApi")}]}[e.toLowerCase()]||[]}function ss(e,t){if(!t.vpc)return;let{cidr:a="10.0.0.0/16",availabilityZones:r=2,natGateways:n=1,enableDnsHostnames:i=!0,enableDnsSupport:s=!0}=t.vpc;e.addResource("VPC","AWS::EC2::VPC",{CidrBlock:a,EnableDnsHostnames:i,EnableDnsSupport:s,Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-vpc")}]}),e.addResource("InternetGateway","AWS::EC2::InternetGateway",{Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-igw")}]}),e.addResource("VPCGatewayAttachment","AWS::EC2::VPCGatewayAttachment",{VpcId:d.ref("VPC"),InternetGatewayId:d.ref("InternetGateway")},{dependsOn:["VPC","InternetGateway"]});let o=[];for(let m=0;m<r;m++){let p=`PublicSubnet${m+1}`;o.push(p),e.addResource(p,"AWS::EC2::Subnet",{VpcId:d.ref("VPC"),CidrBlock:d.select(m,d.cidr(d.getAtt("VPC","CidrBlock"),r*2,8)),AvailabilityZone:d.select(m,d.getAZs()),MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-public-${m+1}`)},{Key:"Type",Value:"public"}]},{dependsOn:"VPC"})}let c=[];for(let m=0;m<r;m++){let p=`PrivateSubnet${m+1}`;c.push(p),e.addResource(p,"AWS::EC2::Subnet",{VpcId:d.ref("VPC"),CidrBlock:d.select(m+r,d.cidr(d.getAtt("VPC","CidrBlock"),r*2,8)),AvailabilityZone:d.select(m,d.getAZs()),MapPublicIpOnLaunch:!1,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-private-${m+1}`)},{Key:"Type",Value:"private"}]},{dependsOn:"VPC"})}let l=[];for(let m=0;m<n;m++){let p=`NatEIP${m+1}`;l.push(p),e.addResource(p,"AWS::EC2::EIP",{Domain:"vpc",Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-nat-eip-${m+1}`)}]},{dependsOn:"VPCGatewayAttachment"})}let u=[];for(let m=0;m<n;m++){let p=`NatGateway${m+1}`;u.push(p);let g=m%r;e.addResource(p,"AWS::EC2::NatGateway",{AllocationId:d.getAtt(l[m],"AllocationId"),SubnetId:d.ref(o[g]),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-nat-${m+1}`)}]},{dependsOn:[l[m],o[g]]})}e.addResource("PublicRouteTable","AWS::EC2::RouteTable",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-public-rt")}]},{dependsOn:"VPC"}),e.addResource("PublicRoute","AWS::EC2::Route",{RouteTableId:d.ref("PublicRouteTable"),DestinationCidrBlock:"0.0.0.0/0",GatewayId:d.ref("InternetGateway")},{dependsOn:["PublicRouteTable","VPCGatewayAttachment"]}),o.forEach((m,p)=>{e.addResource(`PublicSubnetRouteTableAssociation${p+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:d.ref(m),RouteTableId:d.ref("PublicRouteTable")},{dependsOn:[m,"PublicRouteTable"]})}),c.forEach((m,p)=>{let g=`PrivateRouteTable${p+1}`,h=p%n;e.addResource(g,"AWS::EC2::RouteTable",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-private-rt-${p+1}`)}]},{dependsOn:"VPC"}),e.addResource(`PrivateRoute${p+1}`,"AWS::EC2::Route",{RouteTableId:d.ref(g),DestinationCidrBlock:"0.0.0.0/0",NatGatewayId:d.ref(u[h])},{dependsOn:[g,u[h]]}),e.addResource(`PrivateSubnetRouteTableAssociation${p+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:d.ref(m),RouteTableId:d.ref(g)},{dependsOn:[m,g]})}),e.addResource("S3VPCEndpoint","AWS::EC2::VPCEndpoint",{VpcId:d.ref("VPC"),ServiceName:d.sub("com.amazonaws.${AWS::Region}.s3"),VpcEndpointType:"Gateway",RouteTableIds:[d.ref("PublicRouteTable"),...Array.from({length:r},(m,p)=>d.ref(`PrivateRouteTable${p+1}`))]},{dependsOn:"VPC"}),e.addResource("NetworkAcl","AWS::EC2::NetworkAcl",{VpcId:d.ref("VPC"),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-nacl")}]},{dependsOn:"VPC"}),e.addResource("NetworkAclEntryInbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:d.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),e.addResource("NetworkAclEntryOutbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:d.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,Egress:!0,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),e.addOutputs({VPCId:{Description:"VPC ID",Value:d.ref("VPC"),Export:{Name:d.sub("${AWS::StackName}-VPC")}},PublicSubnets:{Description:"Public subnet IDs",Value:d.join(",",o.map((m)=>d.ref(m))),Export:{Name:d.sub("${AWS::StackName}-PublicSubnets")}},PrivateSubnets:{Description:"Private subnet IDs",Value:d.join(",",c.map((m)=>d.ref(m))),Export:{Name:d.sub("${AWS::StackName}-PrivateSubnets")}}})}function os(e,t){for(let[a,r]of Object.entries(t))cs(e,a,r)}function cs(e,t,a){let r=e.toLogicalId(`${t}-queue`),n=a.fifo||!1,i;if(a.deadLetterQueue){let o=`${r}DLQ`;e.addResource(o,"AWS::SQS::Queue",{QueueName:n?d.sub(`\${AWS::StackName}-${t}-dlq.fifo`):d.sub(`\${AWS::StackName}-${t}-dlq`),FifoQueue:n,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}-dlq`)}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),i=d.getAtt(o,"Arn")}let s={QueueName:n?d.sub(`\${AWS::StackName}-${t}.fifo`):d.sub(`\${AWS::StackName}-${t}`),FifoQueue:n,VisibilityTimeout:a.visibilityTimeout||30,MessageRetentionPeriod:a.messageRetentionPeriod||345600,ReceiveMessageWaitTimeSeconds:a.receiveMessageWaitTime||0,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]};if(n&&a.contentBasedDeduplication)s.ContentBasedDeduplication=!0;if(a.deadLetterQueue&&i)s.RedrivePolicy={deadLetterTargetArn:i,maxReceiveCount:a.maxReceiveCount||3};if(e.addResource(r,"AWS::SQS::Queue",s,{dependsOn:a.deadLetterQueue?`${r}DLQ`:void 0,deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),e.addResource(`${r}Policy`,"AWS::SQS::QueuePolicy",{Queues:[d.ref(r)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","events.amazonaws.com","sns.amazonaws.com"]},Action:"sqs:SendMessage",Resource:d.getAtt(r,"Arn"),Condition:{ArnEquals:{"aws:SourceArn":d.sub("arn:aws:*:${AWS::Region}:${AWS::AccountId}:*")}}}]}},{dependsOn:r}),e.addOutputs({[`${r}Url`]:{Description:`${t} queue URL`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-queue-url`)}},[`${r}Arn`]:{Description:`${t} queue ARN`,Value:d.getAtt(r,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t}-queue-arn`)}}}),a.deadLetterQueue)e.addOutputs({[`${r}DLQUrl`]:{Description:`${t} dead letter queue URL`,Value:d.ref(`${r}DLQ`),Export:{Name:d.sub(`\${AWS::StackName}-${t}-dlq-url`)}}})}function ls(e,t){if(t.certificate)us(e,t.certificate);if(t.waf?.enabled)ds(e,t.waf);if(t.securityGroups)for(let[a,r]of Object.entries(t.securityGroups))ms(e,a,r)}function us(e,t){if(!t)return;let a=[t.domain];if(t.subdomains)a.push(...t.subdomains);e.addResource("Certificate","AWS::CertificateManager::Certificate",{DomainName:t.domain,SubjectAlternativeNames:t.subdomains,ValidationMethod:t.validationMethod||"DNS",DomainValidationOptions:a.map((r)=>({DomainName:r,HostedZoneId:d.ref("HostedZone")})),Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-certificate")}]}),e.addOutputs({CertificateArn:{Description:"ACM Certificate ARN",Value:d.ref("Certificate"),Export:{Name:d.sub("${AWS::StackName}-certificate-arn")}}})}function ds(e,t){if(!t)return;let a=[],r=t.rules||["rateLimit","sqlInjection","xss"];if(r.includes("rateLimit"))a.push({Name:"RateLimitRule",Priority:1,Statement:{RateBasedStatement:{Limit:t.rateLimit||2000,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"RateLimitRule"}});let n=a.length+1;if(r.includes("sqlInjection"))a.push({Name:"AWSManagedRulesSQLi",Priority:n++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesSQLiRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesSQLi"}});if(r.includes("xss"))a.push({Name:"AWSManagedRulesXSS",Priority:n++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesXSS"}});if(r.includes("knownBadInputs"))a.push({Name:"AWSManagedRulesKnownBadInputs",Priority:n++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesKnownBadInputs"}});if(r.includes("coreRuleSet"))a.push({Name:"AWSManagedRulesCoreRuleSet",Priority:n++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesCommonRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesCoreRuleSet"}});if(r.includes("linuxRuleSet"))a.push({Name:"AWSManagedRulesLinuxRuleSet",Priority:n++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesLinuxRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesLinuxRuleSet"}});if(r.includes("apiProtection"))a.push({Name:"AWSManagedRulesAPIProtection",Priority:n++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesAmazonIpReputationList"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesAPIProtection"}});if(r.includes("geoBlock"))a.push({Name:"GeoBlockRule",Priority:n++,Statement:{GeoMatchStatement:{CountryCodes:["CN","RU"]}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"GeoBlockRule"}});if(r.includes("connectionLimit"))a.push({Name:"ConnectionLimitRule",Priority:n++,Statement:{RateBasedStatement:{Limit:100,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"ConnectionLimitRule"}});if(e.addResource("WebACL","AWS::WAFv2::WebACL",{Name:d.sub("${AWS::StackName}-waf"),Scope:t.scope||"REGIONAL",DefaultAction:{Allow:{}},Rules:a,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:d.sub("${AWS::StackName}-waf")},Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-waf")}]}),e.hasResource("LoadBalancer"))e.addResource("WebACLAssociation","AWS::WAFv2::WebACLAssociation",{ResourceArn:d.ref("LoadBalancer"),WebACLArn:d.getAtt("WebACL","Arn")},{dependsOn:["WebACL","LoadBalancer"]});e.addOutputs({WebACLId:{Description:"WAF Web ACL ID",Value:d.ref("WebACL"),Export:{Name:d.sub("${AWS::StackName}-waf-id")}},WebACLArn:{Description:"WAF Web ACL ARN",Value:d.getAtt("WebACL","Arn"),Export:{Name:d.sub("${AWS::StackName}-waf-arn")}}})}function ms(e,t,a){if(!a)return;let r=e.toLogicalId(`${t}-security-group`),n=a.ingress?.map((s)=>({IpProtocol:s.protocol,FromPort:s.port,ToPort:s.port,CidrIp:s.cidr,SourceSecurityGroupId:s.source?d.ref(s.source):void 0}))||[],i=a.egress?.map((s)=>({IpProtocol:s.protocol,FromPort:s.port,ToPort:s.port,CidrIp:s.cidr||"0.0.0.0/0"}))||[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}];e.addResource(r,"AWS::EC2::SecurityGroup",{GroupDescription:`Security group for ${t}`,VpcId:d.ref("VPC"),SecurityGroupIngress:n,SecurityGroupEgress:i,Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}-sg`)}]},{dependsOn:"VPC"}),e.addOutputs({[`${r}Id`]:{Description:`${t} security group ID`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-sg-id`)}}})}function ps(e,t){for(let[a,r]of Object.entries(t)){if(r.type==="efs"){hs(e,a,r);continue}gs(e,a,r)}}function gs(e,t,a){let r=e.toLogicalId(`${t}-bucket`),n={BucketName:d.sub(`\${AWS::StackName}-${t}`),Tags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]};if(a.versioning)n.VersioningConfiguration={Status:"Enabled"};if(a.encryption)n.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(!a.public)n.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(a.website)n.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"index.html"};if(a.cors&&a.cors.length>0)n.CorsConfiguration={CorsRules:a.cors.map((i)=>({AllowedOrigins:i.allowedOrigins,AllowedMethods:i.allowedMethods,AllowedHeaders:i.allowedHeaders||["*"],MaxAge:i.maxAge||3600}))};if(a.lifecycleRules&&a.lifecycleRules.length>0)n.LifecycleConfiguration={Rules:a.lifecycleRules.map((i)=>({Id:i.id,Status:i.enabled?"Enabled":"Disabled",ExpirationInDays:i.expirationDays,Transitions:i.transitions?.map((s)=>({TransitionInDays:s.days,StorageClass:s.storageClass}))}))};if(a.intelligentTiering)n.IntelligentTieringConfigurations=[{Id:"EntireBucket",Status:"Enabled",Tierings:[{AccessTier:"ARCHIVE_ACCESS",Days:90},{AccessTier:"DEEP_ARCHIVE_ACCESS",Days:180}]}];if(e.addResource(r,"AWS::S3::Bucket",n,{deletionPolicy:a.versioning?"Retain":"Delete"}),a.public)e.addResource(`${r}Policy`,"AWS::S3::BucketPolicy",{Bucket:d.ref(r),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:"s3:GetObject",Resource:d.join("",[bt.s3Bucket(d.ref(r)),"/*"])}]}},{dependsOn:r});if(e.addOutputs({[`${r}Name`]:{Description:`${t} bucket name`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-bucket`)}},[`${r}Arn`]:{Description:`${t} bucket ARN`,Value:d.getAtt(r,"Arn"),Export:{Name:d.sub(`\${AWS::StackName}-${t}-bucket-arn`)}}}),a.website)e.addOutputs({[`${r}WebsiteURL`]:{Description:`${t} website URL`,Value:d.getAtt(r,"WebsiteURL")}})}function hs(e,t,a){let r=e.toLogicalId(`${t}-efs`),n={Encrypted:a.encryption!==!1,PerformanceMode:a.performanceMode||"generalPurpose",ThroughputMode:a.throughputMode||"bursting",FileSystemTags:[{Key:"Name",Value:d.sub(`\${AWS::StackName}-${t}`)}]};if(a.lifecyclePolicy){if(n.LifecyclePolicies=[],a.lifecyclePolicy.transitionToIA)n.LifecyclePolicies.push({TransitionToIA:`AFTER_${a.lifecyclePolicy.transitionToIA}_DAYS`});if(a.lifecyclePolicy.transitionToPrimaryStorageClass)n.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"})}e.addResource(r,"AWS::EFS::FileSystem",n,{deletionPolicy:"Retain"});let i=2;for(let s=0;s<i;s++)e.addResource(`${r}MountTarget${s+1}`,"AWS::EFS::MountTarget",{FileSystemId:d.ref(r),SubnetId:d.ref(`PrivateSubnet${s+1}`),SecurityGroups:[d.ref("EFSSecurityGroup")]},{dependsOn:[r,`PrivateSubnet${s+1}`]});e.addResource("EFSSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for EFS mount targets",VpcId:d.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:d.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:d.sub("${AWS::StackName}-efs-sg")}]},{dependsOn:"VPC"}),e.addOutputs({[`${r}Id`]:{Description:`${t} EFS file system ID`,Value:d.ref(r),Export:{Name:d.sub(`\${AWS::StackName}-${t}-efs`)}}})}class qa{template;config;resourceDependencies;constructor(e){this.config=e,this.resourceDependencies=new Map,this.template={AWSTemplateFormatVersion:"2010-09-09",Description:`Infrastructure for ${e.project.name} (${e.project.slug})`,Resources:{}}}build(){return this.addParameters(),this.addMappings(),this.addConditions(),this.addResources(),this.initializeOutputs(),this.resolveDependencies(),this.template}addParameters(){this.template.Parameters={Environment:{Type:"String",Default:"production",AllowedValues:["development","staging","production"],Description:"Environment name"}}}addMappings(){this.template.Mappings={RegionMap:{"us-east-1":{AMI:"ami-0f3caa1cf4417e51b"},"us-west-2":{AMI:"ami-0d1cd67c26f5fca19"},"eu-west-1":{AMI:"ami-0bbc25e23a7640b9b"}}}}addConditions(){this.template.Conditions={IsProduction:d.equals(d.ref("Environment"),"production"),HasDomain:d.not([d.equals(this.config.environments?.production?.domain||"","")])}}addResources(){let{infrastructure:e}=this.config;if(!e)return;if(e.network)this.addNetworkResources(e.network);if(e.storage)this.addStorageResources(e.storage);if(e.compute)this.addComputeResources(e.compute);if(e.databases)this.addDatabaseResources(e.databases);if(e.cache)this.addCacheResources(e.cache);if(e.cdn)this.addCDNResources(e.cdn);if(e.apiGateway)this.addApiGatewayResources(e.apiGateway);if(e.functions)this.addFunctionResources(e.functions);if(e.queues)this.addQueueResources(e.queues);if(e.messaging)this.addMessagingResources(e.messaging);if(e.monitoring)this.addMonitoringResources(e.monitoring);if(e.security)this.addSecurityResources(e.security)}initializeOutputs(){let e=this.template.Outputs||{};if(this.template.Outputs={StackName:{Description:"Stack name",Value:d.ref("AWS::StackName"),Export:{Name:d.sub("${AWS::StackName}-Name")}},Region:{Description:"AWS Region",Value:d.ref("AWS::Region"),Export:{Name:d.sub("${AWS::StackName}-Region")}},...e},this.config.environments?.production?.domain)this.template.Outputs.Domain={Description:"Production domain",Value:this.config.environments.production.domain,Condition:"HasDomain"}}addResource(e,t,a,r){let n={Type:t,Properties:a};if(r?.dependsOn)n.DependsOn=r.dependsOn,this.trackDependency(e,r.dependsOn);if(r?.condition)n.Condition=r.condition;if(r?.deletionPolicy)n.DeletionPolicy=r.deletionPolicy;if(r?.updateReplacePolicy)n.UpdateReplacePolicy=r.updateReplacePolicy;this.template.Resources[e]=n}addOutputs(e){this.template.Outputs={...this.template.Outputs,...e}}getOutputs(){return this.template.Outputs||{}}hasResource(e){return e in this.template.Resources}getResource(e){return this.template.Resources[e]}trackDependency(e,t){if(!this.resourceDependencies.has(e))this.resourceDependencies.set(e,new Set);(Array.isArray(t)?t:[t]).forEach((a)=>this.resourceDependencies.get(e).add(a))}resolveDependencies(){let e=new Set,t=new Set,a=(r)=>{if(t.has(r))throw Error(`Circular dependency detected involving resource: ${r}`);if(e.has(r))return!0;e.add(r),t.add(r);let n=this.resourceDependencies.get(r);if(n)for(let i of n)a(i);return t.delete(r),!0};for(let r of this.resourceDependencies.keys())a(r)}toLogicalId(e){return e.split(/[-_\s]/).map((t)=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}addNetworkResources(e){ss(this,e)}addStorageResources(e){ps(this,e)}addComputeResources(e){ji(this,e)}addDatabaseResources(e){qi(this,e)}addFunctionResources(e){Qi(this,e)}addCacheResources(e){_i(this,e)}addQueueResources(e){os(this,e)}addMessagingResources(e){Xi(this,e)}addCDNResources(e){Vi(this,e)}addApiGatewayResources(e){$i(this,e)}addMonitoringResources(e){ts(this,e)}addSecurityResources(e){ls(this,e)}}function Pl(e){return new qa(e).build()}function Il(e){let{name:t,slug:a,domain:r,subdomain:n}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:n&&r?`${n}.${r}`:r}},infrastructure:{storage:{assets:{public:!0,versioning:!1,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"],allowedHeaders:["*"],maxAge:3600}]}},cdn:{enabled:!0,customDomain:r?{domain:n&&r?`${n}.${r}`:r,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0,errorPages:{404:"/index.html",403:"/index.html"}}}}}function Rl(e){let{name:t,slug:a,domain:r,instanceType:n="t3.small",minInstances:i=2,maxInstances:s=10}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:n,ami:"ubuntu-22.04",keyPair:`${a}-key`,autoScaling:{min:i,max:s,desired:i,targetCPU:70},loadBalancer:{type:"application",healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3}},userData:{packages:["nodejs","npm","nginx"],commands:["curl -fsSL https://bun.sh/install | bash","npm install -g pm2"]}}},databases:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.micro",allocatedStorage:20,multiAZ:!0,backupRetentionDays:7,deletionProtection:!0}},cache:{redis:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},security:{certificate:r?{domain:r,subdomains:[`*.${r}`],validationMethod:"DNS"}:void 0}}}}function Nl(e){let{name:t,slug:a,domain:r,taskCpu:n="256",taskMemory:i="512",desiredCount:s=2}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:0}},compute:{fargate:{taskDefinition:{cpu:n,memory:i,containerDefinitions:[{name:"app",image:`${a}-app:latest`,portMappings:[{containerPort:3000}],environment:[],secrets:[]}]},service:{desiredCount:s,healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},autoScaling:{min:s,max:s*5,targetCPU:70,targetMemory:80}},loadBalancer:{type:"application"}}},databases:{dynamodb:{tables:{[`${a}-main`]:{partitionKey:{name:"id",type:"S"},sortKey:{name:"createdAt",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0}}}},functions:{"process-queue":{runtime:"nodejs20.x",handler:"dist/workers/queue.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${a}-queue`}]}},security:{certificate:r?{domain:r,subdomains:[`*.${r}`],validationMethod:"DNS"}:void 0}}}}function Dl(e){let{name:t,slug:a,entry:r,domain:n,runtime:i="nodejs20.x",memory:s=1024,build:o,deploy:c,assets:l,queues:u=!0,scheduler:m="on",region:p="us-east-1"}=e;return{project:{name:t,slug:a,region:p},mode:"serverless",environments:{production:{type:"production",domain:n,app:{kind:"node",runtime:i,entry:r,memory:s,build:o,deploy:c,assets:l,queues:u,scheduler:m,domain:n}}}}}function kl(e){let t=e.database!==!1,a=e.cache!==!1,r=e.queue!==!1;return{project:{name:e.name,slug:e.slug,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:e.domain}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{fargate:{taskDefinition:{cpu:"256",memory:"512",containerDefinitions:[{name:"api",image:e.imageUri,portMappings:[{containerPort:3000}],environment:[{name:"NODE_ENV",value:"production"},{name:"PORT",value:"3000"},{name:"AWS_REGION",value:d.ref("AWS::Region")},...t?[{name:"DB_HOST",value:d.getAtt("PostgresDb","Endpoint.Address")},{name:"DB_PORT",value:d.getAtt("PostgresDb","Endpoint.Port")}]:[],...a?[{name:"REDIS_HOST",value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address")},{name:"REDIS_PORT",value:d.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port")},{name:"REDIS_TLS",value:"true"}]:[],...r?[{name:"QUEUE_URL",value:d.ref("JobsQueue")}]:[],{name:"MAIL_TRANSPORT",value:"ses"}],secrets:t?[{name:"DB_USERNAME",valueFrom:d.sub("${DBSecret}:username::")},{name:"DB_PASSWORD",valueFrom:d.sub("${DBSecret}:password::")}]:[]}]},service:{desiredCount:e.desiredCount||1,healthCheck:{path:"/api/health",interval:30,timeout:5},autoScaling:{min:e.desiredCount||1,max:6,targetCPU:70}},loadBalancer:{type:"application",...e.certificateArn?{customDomain:{domain:e.domain,certificateArn:e.certificateArn}}:{},...e.originVerifySecret?{originVerifyHeader:{name:"X-Origin-Verify",value:e.originVerifySecret}}:{}}}},...t?{databases:{postgres:{engine:"postgres",version:"16",instanceClass:"db.t4g.micro",allocatedStorage:20,maxAllocatedStorage:100,multiAZ:!1,backupRetentionDays:7,deletionProtection:!0}}}:{},...a?{cache:{redis:{nodeType:"cache.t4g.micro",numCacheNodes:2,engine:"redis",engineVersion:"7.1",automaticFailoverEnabled:!0,snapshotRetentionLimit:5}}}:{},...r?{queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0,maxReceiveCount:3,receiveMessageWaitTime:20}}}:{}}}}function $l(e){let{name:t,slug:a,domain:r,apiSubdomain:n="api"}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},storage:{frontend:{public:!0,versioning:!0,website:!0,encryption:!1}},cdn:{enabled:!0,customDomain:{domain:r,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0,errorPages:{404:"/index.html"}},compute:{fargate:{taskDefinition:{cpu:"512",memory:"1024",containerDefinitions:[{name:"api",image:`${a}-api:latest`,portMappings:[{containerPort:3000}]}]},service:{desiredCount:2,healthCheck:{path:"/api/health",interval:30},autoScaling:{min:2,max:10,targetCPU:70}},loadBalancer:{type:"application",customDomain:{domain:`${n}.${r}`,certificateArn:"TO_BE_GENERATED"}}}},databases:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.small",allocatedStorage:50,multiAZ:!0,backupRetentionDays:14,deletionProtection:!0}},cache:{redis:{nodeType:"cache.t3.small",numCacheNodes:2,engine:"redis",engineVersion:"7.0"}},queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0}},security:{certificate:{domain:r,subdomains:[`*.${r}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss"]}}}}}function Ll(e){let{name:t,slug:a,domain:r}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{apiGateway:{type:"HTTP",cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"],allowHeaders:["Content-Type","Authorization"],maxAge:3600},customDomain:r?{domain:r,certificateArn:"TO_BE_GENERATED"}:void 0,throttling:{rateLimit:1e4,burstLimit:5000},authorizer:{type:"JWT",identitySource:"$request.header.Authorization"}},functions:{users:{runtime:"nodejs20.x",handler:"dist/api/users.handler",memory:512,timeout:30,events:[{type:"http",path:"/users",method:"GET"},{type:"http",path:"/users",method:"POST"}]},products:{runtime:"nodejs20.x",handler:"dist/api/products.handler",memory:512,timeout:30,events:[{type:"http",path:"/products",method:"GET"}]}},databases:{dynamodb:{tables:{[`${a}-users`]:{partitionKey:{name:"userId",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"EmailIndex",partitionKey:{name:"email",type:"S"},projection:"ALL"}]},[`${a}-products`]:{partitionKey:{name:"productId",type:"S"},sortKey:{name:"category",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!1}}}},cache:{elasticache:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},security:{certificate:r?{domain:r,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}},monitoring:{alarms:[{metric:"Errors",threshold:10,period:300,evaluationPeriods:1},{metric:"Duration",threshold:3000,period:300,evaluationPeriods:2}]}}}}function Ml(e){let{name:t,slug:a,domain:r,instanceType:n="t3.small"}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:n,ami:"ubuntu-22.04",keyPair:`${a}-key`,autoScaling:{min:2,max:6,desired:2,targetCPU:75},loadBalancer:{type:"application",healthCheck:{path:"/wp-admin/install.php",interval:30}},userData:{packages:["nginx","php8.1-fpm","php8.1-mysql","php8.1-curl","php8.1-gd","php8.1-mbstring","php8.1-xml","php8.1-zip"],commands:["cd /var/www","wget https://wordpress.org/latest.tar.gz","tar -xzf latest.tar.gz","chown -R www-data:www-data wordpress","rm /etc/nginx/sites-enabled/default","systemctl restart nginx","systemctl restart php8.1-fpm"]}}},fileSystem:{uploads:{performanceMode:"generalPurpose",throughputMode:"bursting",encrypted:!0,lifecyclePolicy:{transitionToIA:30},mountPath:"/var/www/wordpress/wp-content/uploads"}},databases:{mysql:{engine:"mysql",version:"8.0",instanceClass:"db.t3.small",allocatedStorage:50,multiAZ:!0,backupRetentionDays:7,deletionProtection:!0,databaseName:"wordpress"}},cache:{redis:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},cdn:{enabled:!0,customDomain:{domain:r,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,origins:[{type:"alb",pathPattern:"/wp-content/*"}]},security:{certificate:{domain:r,subdomains:[`www.${r}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","wordpressRules"]}}}}}function xl(e){let{name:t,slug:a,domain:r,apiDomain:n}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{storage:{static:{public:!0,versioning:!0,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"]}],lifecycleRules:[{id:"DeleteOldVersions",enabled:!0,expirationDays:90}]}},cdn:{enabled:!0,customDomain:{domain:r,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:0,maxTTL:31536000},compress:!0,http3:!0,errorPages:{404:"/404.html",500:"/500.html"},edgeFunctions:[{eventType:"origin-request",functionArn:"TO_BE_CREATED",name:"ssr-handler"}]},functions:{ssr:{runtime:"nodejs20.x",handler:"dist/edge/ssr.handler",memory:512,timeout:5},...n?{api:{runtime:"nodejs20.x",handler:"dist/api/index.handler",memory:1024,timeout:30,events:[{type:"http",path:"/{proxy+}",method:"ANY"}]}}:{}},apiGateway:n?{type:"HTTP",customDomain:{domain:n,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:[r],allowMethods:["GET","POST","PUT","DELETE"],allowHeaders:["Content-Type","Authorization"]}}:void 0,databases:{dynamodb:{tables:{content:{partitionKey:{name:"id",type:"S"},sortKey:{name:"type",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!1}}}},security:{certificate:{domain:r,subdomains:n?[n]:[],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","geoBlock"]}}}}}function Ol(e){let{name:t,slug:a,domain:r,services:n}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:3,natGateways:2}},compute:{services:n.map((i)=>({name:i.name,type:"fargate",taskDefinition:{cpu:i.cpu||"256",memory:i.memory||"512",containerDefinitions:[{name:i.name,image:`${a}-${i.name}:latest`,portMappings:[{containerPort:i.port}],healthCheck:{command:["CMD-SHELL",`curl -f http://localhost:${i.port}/health || exit 1`],interval:30,timeout:5,retries:3}}]},service:{desiredCount:i.desiredCount||2,serviceDiscovery:{enabled:!0,namespace:`${a}.local`},autoScaling:{min:2,max:10,targetCPU:70}}}))},apiGateway:{type:"HTTP",customDomain:{domain:r,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"]},routes:n.map((i)=>({path:`/${i.name}/{proxy+}`,integration:{type:"vpc-link",service:i.name}}))},databases:{dynamodb:{tables:Object.fromEntries(n.map((i)=>[`${a}-${i.name}`,{partitionKey:{name:"id",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0}]))}},queues:{events:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0}},messaging:{topics:{events:{name:`${a}-events`,subscriptions:n.map((i)=>({protocol:"sqs",endpoint:`${a}-${i.name}-queue`,filterPolicy:{service:[i.name]}}))}}},monitoring:{dashboard:{name:`${a}-microservices`,widgets:n.map((i)=>({type:"metric",metrics:[{service:i.name,metric:"CPUUtilization"},{service:i.name,metric:"MemoryUtilization"},{service:i.name,metric:"RequestCount"}]}))},alarms:n.flatMap((i)=>[{name:`${i.name}-high-cpu`,metric:"CPUUtilization",threshold:80,service:i.name},{name:`${i.name}-errors`,metric:"Errors",threshold:10,service:i.name}])},security:{certificate:{domain:r,validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}}}}}function Bl(e){let{name:t,slug:a,domain:r}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{apiGateway:{type:"websocket",customDomain:r?{domain:r,certificateArn:"TO_BE_GENERATED"}:void 0,routes:[{path:"$connect",method:"WEBSOCKET",integration:"websocket-connect"},{path:"$disconnect",method:"WEBSOCKET",integration:"websocket-disconnect"},{path:"$default",method:"WEBSOCKET",integration:"websocket-default"},{path:"sendMessage",method:"WEBSOCKET",integration:"websocket-send-message"},{path:"joinRoom",method:"WEBSOCKET",integration:"websocket-join-room"}]},functions:{connect:{runtime:"nodejs20.x",handler:"dist/websocket/connect.handler",memory:512,timeout:30},disconnect:{runtime:"nodejs20.x",handler:"dist/websocket/disconnect.handler",memory:512,timeout:30},default:{runtime:"nodejs20.x",handler:"dist/websocket/default.handler",memory:512,timeout:30},"send-message":{runtime:"nodejs20.x",handler:"dist/websocket/sendMessage.handler",memory:512,timeout:30},"join-room":{runtime:"nodejs20.x",handler:"dist/websocket/joinRoom.handler",memory:512,timeout:30},broadcast:{runtime:"nodejs20.x",handler:"dist/streams/broadcast.handler",memory:1024,timeout:60,events:[{type:"dynamodb-stream",tableName:`${a}-messages`,startingPosition:"LATEST",batchSize:100}]}},databases:{dynamodb:{tables:{[`${a}-connections`]:{partitionKey:{name:"connectionId",type:"S"},billingMode:"PAY_PER_REQUEST",globalSecondaryIndexes:[{name:"RoomIndex",partitionKey:{name:"roomId",type:"S"},sortKey:{name:"connectionId",type:"S"},projection:"ALL"}]},[`${a}-messages`]:{partitionKey:{name:"roomId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"UserIndex",partitionKey:{name:"userId",type:"S"},sortKey:{name:"timestamp",type:"S"},projection:"ALL"}]},[`${a}-rooms`]:{partitionKey:{name:"roomId",type:"S"},billingMode:"PAY_PER_REQUEST"}}}},cache:{elasticache:{nodeType:"cache.t3.small",numCacheNodes:2,engine:"redis",engineVersion:"7.0"}},monitoring:{alarms:[{metric:"WebSocketConnections",threshold:1e4,evaluationPeriods:1},{metric:"IntegrationLatency",threshold:1000,evaluationPeriods:2}],dashboard:{name:`${a}-realtime`,widgets:[{type:"metric",metrics:["WebSocketConnections","MessagesSent","IntegrationLatency"]}]}},security:{certificate:r?{domain:r,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","connectionLimit"]}}}}}function _l(e){let{name:t,slug:a,retentionDays:r=7}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",infrastructure:{streaming:{dataStream:{name:`${a}-stream`,shardCount:2,retentionPeriod:r*24,encryption:!0}},storage:{raw:{public:!1,versioning:!0,encryption:!0,intelligentTiering:!0,lifecycleRules:[{id:"ArchiveOldData",enabled:!0,transitions:[{days:30,storageClass:"GLACIER"},{days:90,storageClass:"DEEP_ARCHIVE"}]}]},processed:{public:!1,versioning:!0,encryption:!0,intelligentTiering:!0}},functions:{"stream-processor":{runtime:"nodejs20.x",handler:"dist/processors/stream.handler",memory:2048,timeout:300,events:[{type:"kinesis",streamName:`${a}-stream`,batchSize:1000,startingPosition:"LATEST",parallelizationFactor:10}]},transformer:{runtime:"nodejs20.x",handler:"dist/processors/transform.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${a}-raw`,prefix:"incoming/"}]},aggregator:{runtime:"nodejs20.x",handler:"dist/processors/aggregate.handler",memory:2048,timeout:600,events:[{type:"schedule",expression:"cron(0 * * * ? *)"}]}},analytics:{athena:{database:`${a}_analytics`,workgroup:`${a}-workgroup`,outputBucket:`${a}-query-results`,tables:[{name:"raw_events",location:`s3://${a}-raw/events/`,format:"parquet",partitionKeys:["year","month","day"]},{name:"processed_events",location:`s3://${a}-processed/events/`,format:"parquet",partitionKeys:["year","month","day"]}]},glue:{crawlers:[{name:`${a}-crawler`,databaseName:`${a}_analytics`,s3Targets:[`s3://${a}-raw/`,`s3://${a}-processed/`],schedule:"cron(0 2 * * ? *)"}],jobs:[{name:`${a}-etl-job`,scriptLocation:`s3://${a}-scripts/etl.py`,role:`${a}-glue-role`,maxCapacity:10,timeout:120}]}},databases:{dynamodb:{tables:{[`${a}-metadata`]:{partitionKey:{name:"pipelineId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST"}}}},queues:{failedJobs:{fifo:!1,visibilityTimeout:900,messageRetentionPeriod:1209600,deadLetterQueue:!0,maxReceiveCount:3}},workflow:{pipelines:[{name:`${a}-daily-pipeline`,type:"stepFunctions",definition:{StartAt:"ExtractData",States:{ExtractData:{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Next:"TransformData"},TransformData:{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Next:"LoadData"},LoadData:{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",End:!0}}},schedule:"cron(0 0 * * ? *)"}]},monitoring:{dashboard:{name:`${a}-pipeline`,widgets:[{type:"metric",metrics:["KinesisIncomingRecords","LambdaInvocations","S3ObjectsCreated","GlueJobsSucceeded"]}]},alarms:[{metric:"LambdaErrors",threshold:10,evaluationPeriods:1},{metric:"KinesisIteratorAge",threshold:60000,evaluationPeriods:2}]}}}}function Wl(e){let{name:t,slug:a,domain:r,modelS3Path:n=`s3://${a}-models/`,instanceType:i="ml.t3.medium"}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:r}},infrastructure:{storage:{models:{public:!1,versioning:!0,encryption:!0,intelligentTiering:!0},datasets:{public:!1,versioning:!0,encryption:!0,lifecycleRules:[{id:"ArchiveOldDatasets",enabled:!0,transitions:[{days:90,storageClass:"GLACIER"}]}]},predictions:{public:!1,versioning:!1,encryption:!0,lifecycleRules:[{id:"DeleteOldPredictions",enabled:!0,expirationDays:30}]}},machineLearning:{sagemaker:{endpoints:[{name:`${a}-inference`,modelS3Path:n,instanceType:i,initialInstanceCount:1,autoScaling:{minInstances:1,maxInstances:5,targetInvocationsPerInstance:1000}}],trainingJobs:[{name:`${a}-training`,algorithmSpecification:{trainingImage:"TO_BE_SPECIFIED",trainingInputMode:"File"},instanceType:"ml.p3.2xlarge",instanceCount:1,volumeSizeInGB:50,maxRuntimeInSeconds:86400}]}},apiGateway:{type:"HTTP",customDomain:r?{domain:r,certificateArn:"TO_BE_GENERATED"}:void 0,cors:{allowOrigins:["*"],allowMethods:["POST"],allowHeaders:["Content-Type","Authorization"]},throttling:{rateLimit:1000,burstLimit:500}},functions:{predict:{runtime:"python3.11",handler:"handlers/predict.handler",memory:2048,timeout:60,events:[{type:"http",path:"/predict",method:"POST"}],environment:{SAGEMAKER_ENDPOINT:`${a}-inference`,MODEL_BUCKET:`${a}-models`}},"batch-predict":{runtime:"python3.11",handler:"handlers/batchPredict.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${a}-datasets`,suffix:".csv"}]},"trigger-training":{runtime:"python3.11",handler:"handlers/training.handler",memory:1024,timeout:300,events:[{type:"schedule",expression:"cron(0 2 * * ? *)"}]}},databases:{dynamodb:{tables:{[`${a}-predictions`]:{partitionKey:{name:"requestId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0},[`${a}-models`]:{partitionKey:{name:"modelId",type:"S"},sortKey:{name:"version",type:"S"},billingMode:"PAY_PER_REQUEST"}}}},queues:{predictions:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:86400,deadLetterQueue:!0}},monitoring:{dashboard:{name:`${a}-ml`,widgets:[{type:"metric",metrics:["SageMakerInvocations","SageMakerModelLatency","APIGatewayRequests","LambdaErrors"]}]},alarms:[{metric:"SageMakerModelLatency",threshold:1000,evaluationPeriods:2},{metric:"SageMakerInvocationErrors",threshold:10,evaluationPeriods:1}]},security:{certificate:r?{domain:r,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","apiProtection"]}}}}}function Gl(e){let{name:t,slug:a,domain:r,instanceType:n="t3.medium",minInstances:i=2,maxInstances:s=10,databaseEngine:o="mysql",sessionStore:c="redis"}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:r}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:2}},compute:{server:{instanceType:n,ami:"ubuntu-22.04",autoScaling:{min:i,max:s,targetCPU:70,scaleUpCooldown:300,scaleDownCooldown:300},loadBalancer:{type:"application",healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},stickySession:{enabled:!0,duration:86400}},userData:`#!/bin/bash
|
|
2490
2490
|
# Install Node.js or PHP/Python based on app needs
|
|
2491
2491
|
# Configure application server (PM2, Nginx, Apache)
|
|
2492
2492
|
# Mount EFS for shared file storage
|
|
2493
|
-
`}},storage:{uploads:{type:"efs",performanceMode:"generalPurpose",throughputMode:"bursting",encrypted:!0,lifecyclePolicy:{transitionToIA:30}},backups:{public:!1,versioning:!0,encryption:!0,lifecycleRules:[{id:"ArchiveOldBackups",enabled:!0,transitions:[{days:90,storageClass:"GLACIER"}]}]},static:{public:!0,versioning:!1,encryption:!1,cors:[{allowedOrigins:[r||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${a}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:r?{domain:r,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:o==="mysql"?{mysql:{engine:"mysql",version:"8.0",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",innodb_buffer_pool_size:"{DBInstanceClassMemory*3/4}",slow_query_log:"1",long_query_time:"2"}}}:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",shared_buffers:"{DBInstanceClassMemory/4}",log_min_duration_statement:"2000"}}},cache:c==="redis"?{redis:{nodeType:"cache.t3.medium",numCacheNodes:2,engine:"redis",engineVersion:"7.0",port:6379,parameterGroup:{maxmemoryPolicy:"allkeys-lru",timeout:"300"},snapshotRetentionLimit:5,snapshotWindow:"03:00-05:00",automaticFailoverEnabled:!0}}:void 0,queues:{jobs:{fifo:!1,visibilityTimeout:900,messageRetentionPeriod:345600,receiveMessageWaitTime:20,deadLetterQueue:!0,maxReceiveCount:3},emails:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:86400,deadLetterQueue:!0}},functions:{"job-worker":{runtime:"nodejs20.x",handler:"dist/workers/jobs.handler",memory:2048,timeout:900,events:[{type:"sqs",queueName:`${a}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${a}-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:`${a}-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:[`${a}-app`,`${a}-nginx`,`${a}-workers`]}},security:{certificate:r?{domain:r,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","knownBadInputs"]},securityGroups:{alb:{ingress:[{port:80,protocol:"tcp",cidr:"0.0.0.0/0"},{port:443,protocol:"tcp",cidr:"0.0.0.0/0"}]},app:{ingress:[{port:3000,protocol:"tcp",source:"alb-sg"}]},database:{ingress:[{port:o==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...c==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function
|
|
2494
|
-
`),r=null,n,i,s;for(let o of a){let c=o.trim();if(!c||c.startsWith("#")||c.startsWith(";"))continue;let l=c.match(/^\[([^\]]+)\]$/);if(l){if(r===t&&n&&i)return{accessKeyId:n,secretAccessKey:i,sessionToken:s};r=l[1],n=void 0,i=void 0,s=void 0;continue}if(r===t){let[u,...m]=c.split("="),p=m.join("=").trim();switch(u.trim().toLowerCase()){case"aws_access_key_id":n=p;break;case"aws_secret_access_key":i=p;break;case"aws_session_token":s=p;break}}}if(r===t&&n&&i)return{accessKeyId:n,secretAccessKey:i,sessionToken:s};return null}async function
|
|
2495
|
-
`),o=!1;for(let c of s){let l=c.trim();if(l.startsWith("[")){o=l===i;continue}if(o&&l.startsWith("region")){let[,u]=l.split("=");if(u)return u.trim()}}}catch{}return"us-east-1"}async function Os(e){let t=e||await Et(),a=xs(),{signRequest:r}=await tt().then(()=>Ra),n=a.startsWith("us-gov")?`https://sts.${a}.amazonaws.com`:a==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${a}.amazonaws.com`,i="Action=GetCallerIdentity&Version=2011-06-15",s=r({method:"POST",url:n,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...t,service:"sts",region:a}),o=await fetch(s.url,{method:s.method,headers:s.headers,body:s.body});if(!o.ok)throw Error(`Failed to get account ID: ${await o.text()}`);let c=await o.text(),l=Qe(c,"Account");if(!l)throw Error("Failed to parse account ID from response");return l}await tt();await tt();var Ws=5242880,Lt=5242880,_s=5242880;class Za{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 Et(this.credentialOptions)}buildUrl(e,t){let a=t?encodeURIComponent(t).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return t?`${this.endpoint}/${e}/${a}`:`${this.endpoint}/${e}`;let r=new URL(this.endpoint);return r.hostname=`${e}.${r.hostname}`,t?`${r.origin}/${a}`:r.origin}async get(e,t,a={}){let r=await this.getCredentials(),n=this.buildUrl(e,t),i={};if(a.range)i.Range=a.range;if(a.ifModifiedSince)i["If-Modified-Since"]=a.ifModifiedSince.toUTCString();if(a.ifMatch)i["If-Match"]=a.ifMatch;if(a.ifNoneMatch)i["If-None-Match"]=a.ifNoneMatch;let s=new URL(n);if(a.responseContentType)s.searchParams.set("response-content-type",a.responseContentType);if(a.responseContentDisposition)s.searchParams.set("response-content-disposition",a.responseContentDisposition);let o=K({method:"GET",url:s.toString(),headers:i,...r,service:"s3",region:this.region}),c=await fetch(o.url,{method:o.method,headers:o.headers});if(!c.ok&&c.status!==304){let l=await c.text();throw new Y(`Failed to get object: ${l}`,c.status,e,t)}return c}async getText(e,t,a={}){return(await this.get(e,t,a)).text()}async getJSON(e,t,a={}){return(await this.get(e,t,a)).json()}async getBuffer(e,t,a={}){return(await this.get(e,t,a)).arrayBuffer()}async put(e,t,a,r={}){let n,i;if(typeof a==="string")n=new TextEncoder().encode(a).length,i=a;else if(a instanceof ArrayBuffer)n=a.byteLength,i=a;else if(a instanceof Uint8Array)n=a.byteLength,i=a;else if(a instanceof Blob)n=a.size,i=a;else return this.uploadMultipart(e,t,a,{...r,partSize:Lt});if(n>_s){let s=Gs(i).stream();return this.uploadMultipart(e,t,s,{...r,partSize:Lt})}return this.putSimple(e,t,i,n,r)}async putSimple(e,t,a,r,n){let i=await this.getCredentials(),s=this.buildUrl(e,t),o={"Content-Length":String(r),"Content-Type":n.contentType||fa(t)};if(n.contentEncoding)o["Content-Encoding"]=n.contentEncoding;if(n.cacheControl)o["Cache-Control"]=n.cacheControl;if(n.contentDisposition)o["Content-Disposition"]=n.contentDisposition;if(n.storageClass)o["x-amz-storage-class"]=n.storageClass;if(n.serverSideEncryption)o["x-amz-server-side-encryption"]=n.serverSideEncryption;if(n.acl)o["x-amz-acl"]=n.acl;if(n.tagging)o["x-amz-tagging"]=n.tagging;if(n.metadata)for(let[m,p]of Object.entries(n.metadata))o[`x-amz-meta-${m.toLowerCase()}`]=p;let c;if(typeof a==="string")c=a;else if(a instanceof Blob)c=await a.text();else c=new TextDecoder().decode(a instanceof ArrayBuffer?new Uint8Array(a):a);let l=K({method:"PUT",url:s,headers:o,body:c,...i,service:"s3",region:this.region}),u=await fetch(l.url,{method:l.method,headers:l.headers,body:a});if(!u.ok){let m=await u.text();throw new Y(`Failed to put object: ${m}`,u.status,e,t)}return{etag:(u.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,t){let a=await this.getCredentials(),r=this.buildUrl(e,t),n=K({method:"DELETE",url:r,...a,service:"s3",region:this.region}),i=await fetch(n.url,{method:n.method,headers:n.headers});if(!i.ok&&i.status!==204){let s=await i.text();throw new Y(`Failed to delete object: ${s}`,i.status,e,t)}}async deleteMany(e,t){let a=await this.getCredentials(),r=`${this.buildUrl(e)}?delete`,n=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${t.map((g)=>`<Object><Key>${Us(g)}</Key></Object>`).join("")}</Delete>`,i=K({method:"POST",url:r,headers:{"Content-Type":"application/xml"},body:n,...a,service:"s3",region:this.region}),s=await fetch(i.url,{method:i.method,headers:i.headers,body:n});if(!s.ok){let g=await s.text();throw new Y(`Failed to delete objects: ${g}`,s.status,e)}let o=await s.text(),c=[],l=[],u=/<Deleted><Key>([^<]+)<\/Key>/g,m;while((m=u.exec(o))!==null)c.push(m[1]);let p=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((m=p.exec(o))!==null)l.push({key:m[1],error:`${m[2]}: ${m[3]}`});return{deleted:c,errors:l}}async list(e,t={}){let a=await this.getCredentials(),r=new URL(this.buildUrl(e));if(r.searchParams.set("list-type","2"),t.prefix)r.searchParams.set("prefix",t.prefix);if(t.delimiter)r.searchParams.set("delimiter",t.delimiter);if(t.maxKeys)r.searchParams.set("max-keys",String(t.maxKeys));if(t.continuationToken)r.searchParams.set("continuation-token",t.continuationToken);if(t.startAfter)r.searchParams.set("start-after",t.startAfter);let n=K({method:"GET",url:r.toString(),...a,service:"s3",region:this.region}),i=await fetch(n.url,{method:n.method,headers:n.headers});if(!i.ok){let o=await i.text();throw new Y(`Failed to list objects: ${o}`,i.status,e)}let s=await i.text();return Bs(s)}async*listAll(e,t={}){let a;do{let r=await this.list(e,{...t,continuationToken:a});for(let n of r.contents)yield n;a=r.nextContinuationToken}while(a)}async head(e,t){let a=await this.getCredentials(),r=this.buildUrl(e,t),n=K({method:"HEAD",url:r,...a,service:"s3",region:this.region}),i=await fetch(n.url,{method:n.method,headers:n.headers});if(i.status===404)return null;if(!i.ok){let o=await i.text();throw new Y(`Failed to head object: ${o}`,i.status,e,t)}let s={};return i.headers.forEach((o,c)=>{if(c.toLowerCase().startsWith("x-amz-meta-"))s[c.slice(11)]=o}),{contentLength:Number(i.headers.get("Content-Length")||0),contentType:i.headers.get("Content-Type")||"application/octet-stream",etag:(i.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(i.headers.get("Last-Modified")||0),metadata:s,storageClass:i.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:i.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,t){return await this.head(e,t)!==null}async copy(e,t,a,r,n={}){let i=await this.getCredentials(),s=this.buildUrl(a,r),o={"x-amz-copy-source":`/${e}/${encodeURIComponent(t)}`};if(n.metadataDirective)o["x-amz-metadata-directive"]=n.metadataDirective;if(n.contentType)o["Content-Type"]=n.contentType;if(n.storageClass)o["x-amz-storage-class"]=n.storageClass;if(n.acl)o["x-amz-acl"]=n.acl;if(n.metadata)for(let[m,p]of Object.entries(n.metadata))o[`x-amz-meta-${m.toLowerCase()}`]=p;let c=K({method:"PUT",url:s,headers:o,...i,service:"s3",region:this.region}),l=await fetch(c.url,{method:c.method,headers:c.headers});if(!l.ok){let m=await l.text();throw new Y(`Failed to copy object: ${m}`,l.status,a,r)}let u=(await l.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:u?u[1]:""}}async getPresignedUrl(e,t,a={}){let r=await this.getCredentials(),n=this.buildUrl(e,t);return Na({url:n,method:a.method||"GET",expiresIn:a.expiresIn||3600,...r,service:"s3",region:this.region})}async uploadMultipart(e,t,a,r={}){let n=await this.getCredentials(),i=Math.max(r.partSize||Lt,Ws),s,o;if(a instanceof ReadableStream)s=a;else if(a instanceof Blob)s=a.stream(),o=a.size;else{let u=new Blob([a]);s=u.stream(),o=u.size}let{uploadId:c,baseUrl:l}=await this.initiateMultipartUpload(e,t,r);try{let u=await this.uploadParts(e,t,l,c,s,i,n,o,r.concurrency||4,r.onProgress);return await this.completeMultipartUpload(e,t,l,c,u)}catch(u){throw await this.abortMultipartUpload(e,t,c,l).catch(()=>{}),u}}async initiateMultipartUpload(e,t,a){let r=await this.getCredentials(),n=this.buildUrl(e,t),i=`${n}?uploads`,s={"Content-Type":a.contentType||fa(t)};if(a.storageClass)s["x-amz-storage-class"]=a.storageClass;if(a.serverSideEncryption)s["x-amz-server-side-encryption"]=a.serverSideEncryption;if(a.acl)s["x-amz-acl"]=a.acl;if(a.metadata)for(let[m,p]of Object.entries(a.metadata))s[`x-amz-meta-${m.toLowerCase()}`]=p;let o=K({method:"POST",url:i,headers:s,...r,service:"s3",region:this.region}),c=await fetch(o.url,{method:o.method,headers:o.headers});if(!c.ok){let m=await c.text();throw new Y(`Failed to initiate multipart upload: ${m}`,c.status,e,t)}let l=(await c.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!l)throw new Y("Failed to parse upload ID from response",0,e,t);let u=n;if(c.url)try{let m=new URL(c.url);m.search="",u=m.toString()}catch{}return{uploadId:l[1],baseUrl:u}}async uploadParts(e,t,a,r,n,i,s,o,c,l){let u=[],m=n.getReader(),p=1,g=new Uint8Array(0),h=0,y=o?Math.ceil(o/i):void 0,b=new Map,T=async(S,E)=>{let v=`${a}?partNumber=${E}&uploadId=${encodeURIComponent(r)}`,P={"Content-Length":String(S.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},N=K({method:"PUT",url:v,headers:P,...s,service:"s3",region:this.region}),I=await fetch(N.url,{method:N.method,headers:N.headers,body:S,redirect:"error"});if(!I.ok){let M=await I.text();throw new Y(`Failed to upload part ${E}: ${M}`,I.status,e,t)}let D=(I.headers.get("ETag")||"").replace(/"/g,"");if(!D)throw new Y(`Missing ETag for part ${E}`,I.status,e,t);return{partNumber:E,etag:D}},w=async()=>{let S=await Promise.race(b.values());b.delete(S.partNumber),u.push(S)};while(!0){let{done:S,value:E}=await m.read();if(E){let v=new Uint8Array(g.length+E.length);v.set(g),v.set(E,g.length),g=v}while(g.length>=i||S&&g.length>0){let v=g.slice(0,i);g=g.slice(i);let P=p++;if(b.size>=c)await w();if(b.set(P,T(v,P)),h+=v.byteLength,l)l({loaded:h,total:o||h,part:P,totalParts:y||P})}if(S)break}while(b.size>0)await w();return u.sort((S,E)=>S.partNumber-E.partNumber),u}async completeMultipartUpload(e,t,a,r,n){let i=await this.getCredentials(),s=`${a}?uploadId=${encodeURIComponent(r)}`,o=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${n.map((m)=>`<Part><PartNumber>${m.partNumber}</PartNumber><ETag>"${m.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,c=K({method:"POST",url:s,headers:{"Content-Type":"application/xml"},body:o,...i,service:"s3",region:this.region}),l=await fetch(c.url,{method:c.method,headers:c.headers,body:o});if(!l.ok){let m=await l.text();throw new Y(`Failed to complete multipart upload: ${m}`,l.status,e,t)}let u=(await l.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:u?u[1]:""}}async abortMultipartUpload(e,t,a,r){let n=await this.getCredentials(),i=`${r??this.buildUrl(e,t)}?uploadId=${encodeURIComponent(a)}`,s=K({method:"DELETE",url:i,...n,service:"s3",region:this.region});await fetch(s.url,{method:s.method,headers:s.headers})}async emptyAndDeleteBucket(e){let t=[];for await(let i of this.listAll(e,{}))if(t.push(i.key),t.length>=1000)await this.deleteMany(e,t),t=[];if(t.length>0)await this.deleteMany(e,t);let a=await this.getCredentials(),r=this.buildUrl(e),n=K({method:"DELETE",url:r,...a,service:"s3",region:this.region});await fetch(n.url,{method:n.method,headers:n.headers})}}class Y extends Error{statusCode;bucket;key;constructor(e,t,a,r){super(e);this.statusCode=t,this.bucket=a,this.key=r,this.name="S3Error"}}function Bs(e){let t=[],a=[],r=/<Contents>([\s\S]*?)<\/Contents>/g,n;while((n=r.exec(e))!==null){let s=n[1];t.push({key:X(s,"Key")||"",lastModified:new Date(X(s,"LastModified")||0),etag:(X(s,"ETag")||"").replace(/"/g,""),size:Number(X(s,"Size")||0),storageClass:X(s,"StorageClass")||"STANDARD"})}let i=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((n=i.exec(e))!==null)a.push(n[1]);return{contents:t,commonPrefixes:a,isTruncated:X(e,"IsTruncated")==="true",continuationToken:X(e,"ContinuationToken")||void 0,nextContinuationToken:X(e,"NextContinuationToken")||void 0,keyCount:Number(X(e,"KeyCount")||0),maxKeys:Number(X(e,"MaxKeys")||1000),prefix:X(e,"Prefix")||void 0,delimiter:X(e,"Delimiter")||void 0}}function X(e,t){let a=new RegExp(`<${t}>([^<]*)</${t}>`),r=e.match(a);return r?r[1]:null}function Us(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function fa(e){let t=e.split(".").pop()?.toLowerCase();return{html:"text/html",htm:"text/html",css:"text/css",js:"application/javascript",mjs:"application/javascript",json:"application/json",xml:"application/xml",txt:"text/plain",md:"text/markdown",csv:"text/csv",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",ico:"image/x-icon",avif:"image/avif",mp4:"video/mp4",webm:"video/webm",mov:"video/quicktime",avi:"video/x-msvideo",mp3:"audio/mpeg",wav:"audio/wav",ogg:"audio/ogg",pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",zip:"application/zip",gz:"application/gzip",tar:"application/x-tar",rar:"application/vnd.rar","7z":"application/x-7z-compressed",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",eot:"application/vnd.ms-fontobject",wasm:"application/wasm"}[t||""]||"application/octet-stream"}function Gs(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function au(e){return new Za(e)}await tt();class ye extends Error{code;solution;details;constructor(e,t,a,r){super(e);this.code=t,this.solution=a,this.details=r,this.name="CloudError",Error.captureStackTrace?.(this,ye)}toString(){let e=`${this.name} [${this.code}]: ${this.message}`;if(this.solution)e+=`
|
|
2493
|
+
`}},storage:{uploads:{type:"efs",performanceMode:"generalPurpose",throughputMode:"bursting",encrypted:!0,lifecyclePolicy:{transitionToIA:30}},backups:{public:!1,versioning:!0,encryption:!0,lifecycleRules:[{id:"ArchiveOldBackups",enabled:!0,transitions:[{days:90,storageClass:"GLACIER"}]}]},static:{public:!0,versioning:!1,encryption:!1,cors:[{allowedOrigins:[r||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${a}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:r?{domain:r,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:o==="mysql"?{mysql:{engine:"mysql",version:"8.0",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",innodb_buffer_pool_size:"{DBInstanceClassMemory*3/4}",slow_query_log:"1",long_query_time:"2"}}}:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",shared_buffers:"{DBInstanceClassMemory/4}",log_min_duration_statement:"2000"}}},cache:c==="redis"?{redis:{nodeType:"cache.t3.medium",numCacheNodes:2,engine:"redis",engineVersion:"7.0",port:6379,parameterGroup:{maxmemoryPolicy:"allkeys-lru",timeout:"300"},snapshotRetentionLimit:5,snapshotWindow:"03:00-05:00",automaticFailoverEnabled:!0}}:void 0,queues:{jobs:{fifo:!1,visibilityTimeout:900,messageRetentionPeriod:345600,receiveMessageWaitTime:20,deadLetterQueue:!0,maxReceiveCount:3},emails:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:86400,deadLetterQueue:!0}},functions:{"job-worker":{runtime:"nodejs20.x",handler:"dist/workers/jobs.handler",memory:2048,timeout:900,events:[{type:"sqs",queueName:`${a}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${a}-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:`${a}-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:[`${a}-app`,`${a}-nginx`,`${a}-workers`]}},security:{certificate:r?{domain:r,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","knownBadInputs"]},securityGroups:{alb:{ingress:[{port:80,protocol:"tcp",cidr:"0.0.0.0/0"},{port:443,protocol:"tcp",cidr:"0.0.0.0/0"}]},app:{ingress:[{port:3000,protocol:"tcp",source:"alb-sg"}]},database:{ingress:[{port:o==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...c==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function Fl(e){let{name:t,slug:a,domain:r,repository:n,phpVersion:i="8.3",size:s="small",database:o=a.replace(/-/g,"_"),databasePassword:c,sslEmail:l,deployStrategy:u="push",provider:m="hetzner"}=e;return{project:{name:t,slug:a,region:"us-east-1"},mode:"server",cloud:{provider:m},environments:{production:{type:"production",domain:r}},infrastructure:{compute:{mode:"server",size:s,runtime:"php",webServer:"nginx",php:{versions:[i],default:i},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:o,username:o,password:c}},sites:{main:{root:".",type:"laravel",domain:r,phpVersion:i,repository:{...n,strategy:u},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:l}}}}}function Vl(e){let{name:t,slug:a,domain:r,layers:n,phpVersion:i="8.3",architecture:s="x86_64",memory:o=1024,build:c,deploy:l=["migrate --force"],cache:u="dynamodb",scheduler:m="on",region:p="us-east-1"}=e;return{project:{name:t,slug:a,region:p},mode:"serverless",environments:{production:{type:"production",domain:r,app:{kind:"php",runtime:"provided.al2023",phpVersion:i,architecture:s,layers:n,memory:o,build:c,deploy:l,assets:"public",queues:!0,scheduler:m,cache:{driver:u},domain:r}}}}}function Ul(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 ys=Ga,fs="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function Ss(e){let t=e.split(".").filter(Boolean);return t.length<=2?e:t.slice(-2).join(".")}function bs(e){let t=2166136261;for(let a=0;a<e.length;a++)t^=e.charCodeAt(a),t=Math.imul(t,16777619);return t>>>0}var As=20000,Cs=12000;function Ts(e){return As+bs(e)%Cs}function za(e,t){let a=Ss(e);if(a===e)return`dashboard.${a}`;for(let r of t)if(r===a)return`dashboard.${a}`;return`dashboard.${e}`}function Qa(e,t){let a=[],r=e.infrastructure?.dns?.domain;if(r&&!e.cloud?.attachTo)a.push(r);if(t&&e.environments?.[t]?.domain)a.push(e.environments[t].domain);for(let n of Object.values(e.sites??{})){let i=n;if(!i||i.redirect)continue;let s=i.domain;if(typeof s==="string")a.push(s);else if(Array.isArray(s))a.push(...s.filter((o)=>typeof o==="string"))}return a.filter((n)=>n&&!n.startsWith("dashboard."))}function vs(e,t,a){if(a)return a;let r=Qa(e,t),n=r[0];if(!n)return null;return za(n,r)}function ws(e,t,a){if(a)return[a];let r=Qa(e,t),n=[];for(let i of r){let s=za(i,r);if(!n.includes(s))n.push(s)}return n}function Es(e){return Object.entries(e.sites??{}).some(([t,a])=>{if(!a)return!1;let r=a.root??"";return Ps(t)||r==="ui/dist"||r.endsWith("/ui/dist")||r.endsWith("/dist/ui")})}var Ja="dashboard-";function ya(e){return Ja+e.replace(/^dashboard\./,"").replace(/\./g,"-")}function Ps(e){return e==="dashboard"||e.startsWith(Ja)}function Is(e,t,a){if(Es(e))return[];if(e.cloud?.attachTo)return[];let r=a.password?{auth:{username:a.username||"admin",password:a.password,realm:a.realm}}:{},n=a.build===!1||a.build===void 0?{}:{build:a.build};if(a.live!==!1){let i=vs(e,t,a.domain);if(!i)return[];let s=a.port??Ts(i),o=e.infrastructure?.appDatabase??e.infrastructure?.compute?.database,c={root:a.uiRoot,deploy:"server",domain:i,preStart:["bun install --production --no-save"],start:`bun ${fs} --box --host 127.0.0.1 --port ${s}`,port:s,cpuWeight:10,ioWeight:10,tasksMax:128,env:{APP_ENV:"production",NODE_ENV:"production",TS_CLOUD_DASHBOARD_TELEMETRY:"1",...o?.password?{TS_CLOUD_DASHBOARD_DB_PASSWORD:o.password}:{}},zeroDowntime:!1,sharedPaths:[ys],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:ya(i),site:c}]}return ws(e,t,a.domain).map((i)=>({name:ya(i),site:{root:a.uiRoot,deploy:"server",type:"static",domain:i,ssl:{provider:"letsencrypt"},...n,...r}}))}function jl(e,t,a){return Is(e,t,a)[0]??null}function qt(e,t){let a={...e};for(let r in t){let n=t[r],i=a[r];if(n===void 0)continue;if(Array.isArray(n)&&Array.isArray(i))a[r]=[...i,...n];else if(typeof n==="object"&&n!==null&&!Array.isArray(n)&&typeof i==="object"&&i!==null&&!Array.isArray(i))a[r]=qt(i,n);else a[r]=n}return a}function fa(e,t){return qt(e,t)}function Kl(...e){return e.reduce((t,a)=>qt(t,a),{})}function Hl(e,t){return(a)=>{let r=e(a);if(typeof t==="function")return fa(r,t(r,a));return fa(r,t)}}function We(e){return{infrastructure:e}}function ql(e){return We({monitoring:e})}function zl(e){return We({security:e})}function Ql(e){return We({databases:e})}function Jl(e){return We({cache:e})}function Yl(e){return We({cdn:e})}function Zl(e){return We({queues:e})}at();function Rs(){let e=process.env.AWS_ACCESS_KEY_ID,t=process.env.AWS_SECRET_ACCESS_KEY;if(!e||!t)return null;return{accessKeyId:e,secretAccessKey:t,sessionToken:process.env.AWS_SESSION_TOKEN}}function Ns(e){let t=e?.profile||process.env.AWS_PROFILE||"default",a=e?.credentialsFile||Xa(Za(),".aws","credentials");if(!Ya(a))return null;try{let r=zt(a,"utf-8");return Ds(r,t)}catch{return null}}function Ds(e,t){let a=e.split(`
|
|
2494
|
+
`),r=null,n,i,s;for(let o of a){let c=o.trim();if(!c||c.startsWith("#")||c.startsWith(";"))continue;let l=c.match(/^\[([^\]]+)\]$/);if(l){if(r===t&&n&&i)return{accessKeyId:n,secretAccessKey:i,sessionToken:s};r=l[1],n=void 0,i=void 0,s=void 0;continue}if(r===t){let[u,...m]=c.split("="),p=m.join("=").trim();switch(u.trim().toLowerCase()){case"aws_access_key_id":n=p;break;case"aws_secret_access_key":i=p;break;case"aws_session_token":s=p;break}}}if(r===t&&n&&i)return{accessKeyId:n,secretAccessKey:i,sessionToken:s};return null}async function ks(e){let t=e?.timeout??1000,a="http://169.254.169.254";try{let r=await Xe("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},t);if(!r.ok)return null;let n=await r.text(),i=await Xe("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":n}},t);if(!i.ok)return null;let s=(await i.text()).trim(),o=await Xe(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${s}`,{headers:{"X-aws-ec2-metadata-token":n}},t);if(!o.ok)return null;let c=await o.json();return{accessKeyId:c.AccessKeyId,secretAccessKey:c.SecretAccessKey,sessionToken:c.Token,expiration:new Date(c.Expiration)}}catch{return null}}async function $s(e){let t=e?.timeout??1000,a=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,r=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,n=null;if(a)n=`http://169.254.170.2${a}`;else if(r)n=r;if(!n)return null;try{let i={},s=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(s)i.Authorization=s;let o=await Xe(n,{headers:i},t);if(!o.ok)return null;let c=await o.json();return{accessKeyId:c.AccessKeyId,secretAccessKey:c.SecretAccessKey,sessionToken:c.Token,expiration:new Date(c.Expiration)}}catch{return null}}async function Ls(e){let t=e?.timeout??5000,a=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,r=process.env.AWS_ROLE_ARN,n=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!a||!r)return null;try{let i=zt(a,"utf-8").trim(),s=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION||"us-east-1",o=s.startsWith("us-gov")?`https://sts.${s}.amazonaws.com`:s==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${s}.amazonaws.com`,c=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:r,RoleSessionName:n,WebIdentityToken:i}),l=await Xe(`${o}/?${c.toString()}`,{method:"POST"},t);if(!l.ok)return null;let u=await l.text(),m=Je(u,"AccessKeyId"),p=Je(u,"SecretAccessKey"),g=Je(u,"SessionToken"),h=Je(u,"Expiration");if(!m||!p)return null;return{accessKeyId:m,secretAccessKey:p,sessionToken:g??void 0,expiration:h?new Date(h):void 0}}catch{return null}}async function Pt(e){let t=Rs();if(t)return t;let a=Ns(e);if(a)return a;let r=await Ls(e);if(r)return r;let n=await $s(e);if(n)return n;let i=await ks(e);if(i)return i;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 au(e){let t=null,a=null;return async()=>{if(t){if(!t.expiration)return t;let r=300000;if(t.expiration.getTime()-Date.now()>r)return t}if(a)return a;return a=Pt(e).then((r)=>(t=r,a=null,r)).catch((r)=>{throw a=null,r}),a}}async function Xe(e,t,a){let r=new AbortController,n=setTimeout(()=>r.abort(),a);try{let i=await fetch(e,{...t,signal:r.signal});return clearTimeout(n),i}catch(i){throw clearTimeout(n),i}}function Je(e,t){let a=new RegExp(`<${t}>([^<]+)</${t}>`),r=e.match(a);return r?r[1]:null}async function Ms(e){return Pt({profile:e})}function xs(e){let t=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(t)return t;let a=Xa(Za(),".aws","config");if(Ya(a))try{let r=zt(a,"utf-8"),n=e||process.env.AWS_PROFILE||"default",i=n==="default"?"[default]":`[profile ${n}]`,s=r.split(`
|
|
2495
|
+
`),o=!1;for(let c of s){let l=c.trim();if(l.startsWith("[")){o=l===i;continue}if(o&&l.startsWith("region")){let[,u]=l.split("=");if(u)return u.trim()}}}catch{}return"us-east-1"}async function Os(e){let t=e||await Pt(),a=xs(),{signRequest:r}=await at().then(()=>Na),n=a.startsWith("us-gov")?`https://sts.${a}.amazonaws.com`:a==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${a}.amazonaws.com`,i="Action=GetCallerIdentity&Version=2011-06-15",s=r({method:"POST",url:n,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...t,service:"sts",region:a}),o=await fetch(s.url,{method:s.method,headers:s.headers,body:s.body});if(!o.ok)throw Error(`Failed to get account ID: ${await o.text()}`);let c=await o.text(),l=Je(c,"Account");if(!l)throw Error("Failed to parse account ID from response");return l}await at();await at();var Bs=5242880,Mt=5242880,_s=5242880;class er{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 Pt(this.credentialOptions)}buildUrl(e,t){let a=t?encodeURIComponent(t).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return t?`${this.endpoint}/${e}/${a}`:`${this.endpoint}/${e}`;let r=new URL(this.endpoint);return r.hostname=`${e}.${r.hostname}`,t?`${r.origin}/${a}`:r.origin}async get(e,t,a={}){let r=await this.getCredentials(),n=this.buildUrl(e,t),i={};if(a.range)i.Range=a.range;if(a.ifModifiedSince)i["If-Modified-Since"]=a.ifModifiedSince.toUTCString();if(a.ifMatch)i["If-Match"]=a.ifMatch;if(a.ifNoneMatch)i["If-None-Match"]=a.ifNoneMatch;let s=new URL(n);if(a.responseContentType)s.searchParams.set("response-content-type",a.responseContentType);if(a.responseContentDisposition)s.searchParams.set("response-content-disposition",a.responseContentDisposition);let o=K({method:"GET",url:s.toString(),headers:i,...r,service:"s3",region:this.region}),c=await fetch(o.url,{method:o.method,headers:o.headers});if(!c.ok&&c.status!==304){let l=await c.text();throw new Z(`Failed to get object: ${l}`,c.status,e,t)}return c}async getText(e,t,a={}){return(await this.get(e,t,a)).text()}async getJSON(e,t,a={}){return(await this.get(e,t,a)).json()}async getBuffer(e,t,a={}){return(await this.get(e,t,a)).arrayBuffer()}async put(e,t,a,r={}){let n,i;if(typeof a==="string")n=new TextEncoder().encode(a).length,i=a;else if(a instanceof ArrayBuffer)n=a.byteLength,i=a;else if(a instanceof Uint8Array)n=a.byteLength,i=a;else if(a instanceof Blob)n=a.size,i=a;else return this.uploadMultipart(e,t,a,{...r,partSize:Mt});if(n>_s){let s=Fs(i).stream();return this.uploadMultipart(e,t,s,{...r,partSize:Mt})}return this.putSimple(e,t,i,n,r)}async putSimple(e,t,a,r,n){let i=await this.getCredentials(),s=this.buildUrl(e,t),o={"Content-Length":String(r),"Content-Type":n.contentType||Sa(t)};if(n.contentEncoding)o["Content-Encoding"]=n.contentEncoding;if(n.cacheControl)o["Cache-Control"]=n.cacheControl;if(n.contentDisposition)o["Content-Disposition"]=n.contentDisposition;if(n.storageClass)o["x-amz-storage-class"]=n.storageClass;if(n.serverSideEncryption)o["x-amz-server-side-encryption"]=n.serverSideEncryption;if(n.acl)o["x-amz-acl"]=n.acl;if(n.tagging)o["x-amz-tagging"]=n.tagging;if(n.metadata)for(let[m,p]of Object.entries(n.metadata))o[`x-amz-meta-${m.toLowerCase()}`]=p;let c;if(typeof a==="string")c=a;else if(a instanceof Blob)c=await a.text();else c=new TextDecoder().decode(a instanceof ArrayBuffer?new Uint8Array(a):a);let l=K({method:"PUT",url:s,headers:o,body:c,...i,service:"s3",region:this.region}),u=await fetch(l.url,{method:l.method,headers:l.headers,body:a});if(!u.ok){let m=await u.text();throw new Z(`Failed to put object: ${m}`,u.status,e,t)}return{etag:(u.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,t){let a=await this.getCredentials(),r=this.buildUrl(e,t),n=K({method:"DELETE",url:r,...a,service:"s3",region:this.region}),i=await fetch(n.url,{method:n.method,headers:n.headers});if(!i.ok&&i.status!==204){let s=await i.text();throw new Z(`Failed to delete object: ${s}`,i.status,e,t)}}async deleteMany(e,t){let a=await this.getCredentials(),r=`${this.buildUrl(e)}?delete`,n=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${t.map((g)=>`<Object><Key>${Gs(g)}</Key></Object>`).join("")}</Delete>`,i=K({method:"POST",url:r,headers:{"Content-Type":"application/xml"},body:n,...a,service:"s3",region:this.region}),s=await fetch(i.url,{method:i.method,headers:i.headers,body:n});if(!s.ok){let g=await s.text();throw new Z(`Failed to delete objects: ${g}`,s.status,e)}let o=await s.text(),c=[],l=[],u=/<Deleted><Key>([^<]+)<\/Key>/g,m;while((m=u.exec(o))!==null)c.push(m[1]);let p=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((m=p.exec(o))!==null)l.push({key:m[1],error:`${m[2]}: ${m[3]}`});return{deleted:c,errors:l}}async list(e,t={}){let a=await this.getCredentials(),r=new URL(this.buildUrl(e));if(r.searchParams.set("list-type","2"),t.prefix)r.searchParams.set("prefix",t.prefix);if(t.delimiter)r.searchParams.set("delimiter",t.delimiter);if(t.maxKeys)r.searchParams.set("max-keys",String(t.maxKeys));if(t.continuationToken)r.searchParams.set("continuation-token",t.continuationToken);if(t.startAfter)r.searchParams.set("start-after",t.startAfter);let n=K({method:"GET",url:r.toString(),...a,service:"s3",region:this.region}),i=await fetch(n.url,{method:n.method,headers:n.headers});if(!i.ok){let o=await i.text();throw new Z(`Failed to list objects: ${o}`,i.status,e)}let s=await i.text();return Ws(s)}async*listAll(e,t={}){let a;do{let r=await this.list(e,{...t,continuationToken:a});for(let n of r.contents)yield n;a=r.nextContinuationToken}while(a)}async head(e,t){let a=await this.getCredentials(),r=this.buildUrl(e,t),n=K({method:"HEAD",url:r,...a,service:"s3",region:this.region}),i=await fetch(n.url,{method:n.method,headers:n.headers});if(i.status===404)return null;if(!i.ok){let o=await i.text();throw new Z(`Failed to head object: ${o}`,i.status,e,t)}let s={};return i.headers.forEach((o,c)=>{if(c.toLowerCase().startsWith("x-amz-meta-"))s[c.slice(11)]=o}),{contentLength:Number(i.headers.get("Content-Length")||0),contentType:i.headers.get("Content-Type")||"application/octet-stream",etag:(i.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(i.headers.get("Last-Modified")||0),metadata:s,storageClass:i.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:i.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,t){return await this.head(e,t)!==null}async copy(e,t,a,r,n={}){let i=await this.getCredentials(),s=this.buildUrl(a,r),o={"x-amz-copy-source":`/${e}/${encodeURIComponent(t)}`};if(n.metadataDirective)o["x-amz-metadata-directive"]=n.metadataDirective;if(n.contentType)o["Content-Type"]=n.contentType;if(n.storageClass)o["x-amz-storage-class"]=n.storageClass;if(n.acl)o["x-amz-acl"]=n.acl;if(n.metadata)for(let[m,p]of Object.entries(n.metadata))o[`x-amz-meta-${m.toLowerCase()}`]=p;let c=K({method:"PUT",url:s,headers:o,...i,service:"s3",region:this.region}),l=await fetch(c.url,{method:c.method,headers:c.headers});if(!l.ok){let m=await l.text();throw new Z(`Failed to copy object: ${m}`,l.status,a,r)}let u=(await l.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:u?u[1]:""}}async getPresignedUrl(e,t,a={}){let r=await this.getCredentials(),n=this.buildUrl(e,t);return Da({url:n,method:a.method||"GET",expiresIn:a.expiresIn||3600,...r,service:"s3",region:this.region})}async uploadMultipart(e,t,a,r={}){let n=await this.getCredentials(),i=Math.max(r.partSize||Mt,Bs),s,o;if(a instanceof ReadableStream)s=a;else if(a instanceof Blob)s=a.stream(),o=a.size;else{let u=new Blob([a]);s=u.stream(),o=u.size}let{uploadId:c,baseUrl:l}=await this.initiateMultipartUpload(e,t,r);try{let u=await this.uploadParts(e,t,l,c,s,i,n,o,r.concurrency||4,r.onProgress);return await this.completeMultipartUpload(e,t,l,c,u)}catch(u){throw await this.abortMultipartUpload(e,t,c,l).catch(()=>{}),u}}async initiateMultipartUpload(e,t,a){let r=await this.getCredentials(),n=this.buildUrl(e,t),i=`${n}?uploads`,s={"Content-Type":a.contentType||Sa(t)};if(a.storageClass)s["x-amz-storage-class"]=a.storageClass;if(a.serverSideEncryption)s["x-amz-server-side-encryption"]=a.serverSideEncryption;if(a.acl)s["x-amz-acl"]=a.acl;if(a.metadata)for(let[m,p]of Object.entries(a.metadata))s[`x-amz-meta-${m.toLowerCase()}`]=p;let o=K({method:"POST",url:i,headers:s,...r,service:"s3",region:this.region}),c=await fetch(o.url,{method:o.method,headers:o.headers});if(!c.ok){let m=await c.text();throw new Z(`Failed to initiate multipart upload: ${m}`,c.status,e,t)}let l=(await c.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!l)throw new Z("Failed to parse upload ID from response",0,e,t);let u=n;if(c.url)try{let m=new URL(c.url);m.search="",u=m.toString()}catch{}return{uploadId:l[1],baseUrl:u}}async uploadParts(e,t,a,r,n,i,s,o,c,l){let u=[],m=n.getReader(),p=1,g=new Uint8Array(0),h=0,y=o?Math.ceil(o/i):void 0,b=new Map,T=async(S,E)=>{let v=`${a}?partNumber=${E}&uploadId=${encodeURIComponent(r)}`,P={"Content-Length":String(S.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},N=K({method:"PUT",url:v,headers:P,...s,service:"s3",region:this.region}),I=await fetch(N.url,{method:N.method,headers:N.headers,body:S,redirect:"error"});if(!I.ok){let L=await I.text();throw new Z(`Failed to upload part ${E}: ${L}`,I.status,e,t)}let D=(I.headers.get("ETag")||"").replace(/"/g,"");if(!D)throw new Z(`Missing ETag for part ${E}`,I.status,e,t);return{partNumber:E,etag:D}},w=async()=>{let S=await Promise.race(b.values());b.delete(S.partNumber),u.push(S)};while(!0){let{done:S,value:E}=await m.read();if(E){let v=new Uint8Array(g.length+E.length);v.set(g),v.set(E,g.length),g=v}while(g.length>=i||S&&g.length>0){let v=g.slice(0,i);g=g.slice(i);let P=p++;if(b.size>=c)await w();if(b.set(P,T(v,P)),h+=v.byteLength,l)l({loaded:h,total:o||h,part:P,totalParts:y||P})}if(S)break}while(b.size>0)await w();return u.sort((S,E)=>S.partNumber-E.partNumber),u}async completeMultipartUpload(e,t,a,r,n){let i=await this.getCredentials(),s=`${a}?uploadId=${encodeURIComponent(r)}`,o=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${n.map((m)=>`<Part><PartNumber>${m.partNumber}</PartNumber><ETag>"${m.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,c=K({method:"POST",url:s,headers:{"Content-Type":"application/xml"},body:o,...i,service:"s3",region:this.region}),l=await fetch(c.url,{method:c.method,headers:c.headers,body:o});if(!l.ok){let m=await l.text();throw new Z(`Failed to complete multipart upload: ${m}`,l.status,e,t)}let u=(await l.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:u?u[1]:""}}async abortMultipartUpload(e,t,a,r){let n=await this.getCredentials(),i=`${r??this.buildUrl(e,t)}?uploadId=${encodeURIComponent(a)}`,s=K({method:"DELETE",url:i,...n,service:"s3",region:this.region});await fetch(s.url,{method:s.method,headers:s.headers})}async emptyAndDeleteBucket(e){let t=[];for await(let i of this.listAll(e,{}))if(t.push(i.key),t.length>=1000)await this.deleteMany(e,t),t=[];if(t.length>0)await this.deleteMany(e,t);let a=await this.getCredentials(),r=this.buildUrl(e),n=K({method:"DELETE",url:r,...a,service:"s3",region:this.region});await fetch(n.url,{method:n.method,headers:n.headers})}}class Z extends Error{statusCode;bucket;key;constructor(e,t,a,r){super(e);this.statusCode=t,this.bucket=a,this.key=r,this.name="S3Error"}}function Ws(e){let t=[],a=[],r=/<Contents>([\s\S]*?)<\/Contents>/g,n;while((n=r.exec(e))!==null){let s=n[1];t.push({key:X(s,"Key")||"",lastModified:new Date(X(s,"LastModified")||0),etag:(X(s,"ETag")||"").replace(/"/g,""),size:Number(X(s,"Size")||0),storageClass:X(s,"StorageClass")||"STANDARD"})}let i=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((n=i.exec(e))!==null)a.push(n[1]);return{contents:t,commonPrefixes:a,isTruncated:X(e,"IsTruncated")==="true",continuationToken:X(e,"ContinuationToken")||void 0,nextContinuationToken:X(e,"NextContinuationToken")||void 0,keyCount:Number(X(e,"KeyCount")||0),maxKeys:Number(X(e,"MaxKeys")||1000),prefix:X(e,"Prefix")||void 0,delimiter:X(e,"Delimiter")||void 0}}function X(e,t){let a=new RegExp(`<${t}>([^<]*)</${t}>`),r=e.match(a);return r?r[1]:null}function Gs(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function Sa(e){let t=e.split(".").pop()?.toLowerCase();return{html:"text/html",htm:"text/html",css:"text/css",js:"application/javascript",mjs:"application/javascript",json:"application/json",xml:"application/xml",txt:"text/plain",md:"text/markdown",csv:"text/csv",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",ico:"image/x-icon",avif:"image/avif",mp4:"video/mp4",webm:"video/webm",mov:"video/quicktime",avi:"video/x-msvideo",mp3:"audio/mpeg",wav:"audio/wav",ogg:"audio/ogg",pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",zip:"application/zip",gz:"application/gzip",tar:"application/x-tar",rar:"application/vnd.rar","7z":"application/x-7z-compressed",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",eot:"application/vnd.ms-fontobject",wasm:"application/wasm"}[t||""]||"application/octet-stream"}function Fs(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function ru(e){return new er(e)}await at();class fe extends Error{code;solution;details;constructor(e,t,a,r){super(e);this.code=t,this.solution=a,this.details=r,this.name="CloudError",Error.captureStackTrace?.(this,fe)}toString(){let e=`${this.name} [${this.code}]: ${this.message}`;if(this.solution)e+=`
|
|
2496
2496
|
|
|
2497
2497
|
\uD83D\uDCA1 Solution: ${this.solution}`;if(this.details&&Object.keys(this.details).length>0){e+=`
|
|
2498
2498
|
|
|
2499
2499
|
Details:`;for(let[t,a]of Object.entries(this.details))e+=`
|
|
2500
|
-
${t}: ${JSON.stringify(a)}`}return e}}class
|
|
2500
|
+
${t}: ${JSON.stringify(a)}`}return e}}class pt extends fe{constructor(e,t,a){super(e,"CONFIG_ERROR",t,a);this.name="ConfigurationError"}}class Ie extends fe{constructor(e,t,a){super(e,"CREDENTIAL_ERROR",t,a);this.name="CredentialError"}}class Vs extends fe{constructor(e,t,a){super(e,"DEPLOYMENT_ERROR",t,a);this.name="DeploymentError"}}class tr extends fe{constructor(e,t,a){super(e,"VALIDATION_ERROR",t,a);this.name="ValidationError"}}class Us extends fe{statusCode;constructor(e,t,a,r){super(e,"AWS_API_ERROR",a,r);this.statusCode=t,this.name="AWSAPIError"}}var js={NO_CREDENTIALS:{message:"AWS credentials not found",solution:`Configure AWS credentials using one of these methods:
|
|
2501
2501
|
1. Set environment variables: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
|
|
2502
2502
|
2. Create ~/.aws/credentials file with your credentials
|
|
2503
2503
|
3. Use an IAM role (for EC2 instances)
|
|
2504
|
-
4. Run 'aws configure' if you have AWS CLI installed`},INVALID_CREDENTIALS:{message:"AWS credentials are invalid",solution:"Verify your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are correct. Run: aws sts get-caller-identity"},EXPIRED_CREDENTIALS:{message:"AWS credentials have expired",solution:"Refresh your AWS credentials. If using temporary credentials, generate new ones."},MISSING_CONFIG:{message:"Configuration file not found",solution:"Create a cloud.config.ts file in your project root. Use: cloud init"},INVALID_CONFIG:{message:"Configuration is invalid",solution:"Check your cloud.config.ts file for syntax errors. Use: cloud config:validate"},MISSING_REQUIRED_FIELD:{message:"Required configuration field is missing",solution:"Add the missing field to your cloud.config.ts file"},INVALID_REGION:{message:"AWS region is invalid",solution:"Use a valid AWS region like us-east-1, us-west-2, eu-west-1, etc."},STACK_ALREADY_EXISTS:{message:"CloudFormation stack already exists",solution:"Use: cloud deploy --update to update the existing stack, or cloud destroy to delete it first"},STACK_IN_PROGRESS:{message:"Stack operation already in progress",solution:"Wait for the current operation to complete, or cancel it in the AWS Console"},INSUFFICIENT_PERMISSIONS:{message:"Insufficient IAM permissions",solution:"Ensure your IAM user/role has the necessary permissions for CloudFormation and the resources you're deploying"},RESOURCE_LIMIT_EXCEEDED:{message:"AWS service limit exceeded",solution:"Request a service limit increase in the AWS Console, or clean up unused resources"},ROLLBACK_COMPLETE:{message:"Stack creation failed and rolled back",solution:"Check the CloudFormation events to see which resource failed. Fix the issue and try again."},CIRCULAR_DEPENDENCY:{message:"Circular dependency detected in resources",solution:"Review your resource dependencies and remove the circular reference"},INVALID_RESOURCE_NAME:{message:"Resource name contains invalid characters",solution:"Use only alphanumeric characters and hyphens in resource names"},DUPLICATE_RESOURCE:{message:"Duplicate resource name detected",solution:"Ensure all resource names are unique in your configuration"},VPC_CIDR_CONFLICT:{message:"VPC CIDR block conflicts with existing VPC",solution:"Use a different CIDR block that doesn't overlap with existing VPCs"},SUBNET_CIDR_INVALID:{message:"Subnet CIDR block is invalid or outside VPC range",solution:"Ensure subnet CIDR is within the VPC CIDR range and properly sized"},DB_INSTANCE_LIMIT:{message:"RDS instance limit reached",solution:"Delete unused RDS instances or request a limit increase"},INVALID_DB_NAME:{message:"Database name contains invalid characters",solution:"Use only alphanumeric characters and underscores, starting with a letter"},BUCKET_ALREADY_EXISTS:{message:"S3 bucket name already exists globally",solution:"S3 bucket names must be globally unique. Try a different name with your organization prefix"},INVALID_BUCKET_NAME:{message:"S3 bucket name is invalid",solution:"Use lowercase letters, numbers, and hyphens. Must start/end with letter/number. 3-63 characters."},TEMPLATE_TOO_LARGE:{message:"CloudFormation template exceeds size limit",solution:"Split your infrastructure into multiple stacks or use nested stacks"},INVALID_TEMPLATE:{message:"CloudFormation template is invalid",solution:"Validate your template with: cloud config:validate"},PARAMETER_NOT_FOUND:{message:"CloudFormation parameter not found",solution:"Check that all referenced parameters are defined in your template"}};function Ks(e){return js[e]}function
|
|
2505
|
-
Stack trace:`),console.error(t.stack)}}static success(e){console.log(`✔ ${e}`)}}function
|
|
2504
|
+
4. Run 'aws configure' if you have AWS CLI installed`},INVALID_CREDENTIALS:{message:"AWS credentials are invalid",solution:"Verify your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are correct. Run: aws sts get-caller-identity"},EXPIRED_CREDENTIALS:{message:"AWS credentials have expired",solution:"Refresh your AWS credentials. If using temporary credentials, generate new ones."},MISSING_CONFIG:{message:"Configuration file not found",solution:"Create a cloud.config.ts file in your project root. Use: cloud init"},INVALID_CONFIG:{message:"Configuration is invalid",solution:"Check your cloud.config.ts file for syntax errors. Use: cloud config:validate"},MISSING_REQUIRED_FIELD:{message:"Required configuration field is missing",solution:"Add the missing field to your cloud.config.ts file"},INVALID_REGION:{message:"AWS region is invalid",solution:"Use a valid AWS region like us-east-1, us-west-2, eu-west-1, etc."},STACK_ALREADY_EXISTS:{message:"CloudFormation stack already exists",solution:"Use: cloud deploy --update to update the existing stack, or cloud destroy to delete it first"},STACK_IN_PROGRESS:{message:"Stack operation already in progress",solution:"Wait for the current operation to complete, or cancel it in the AWS Console"},INSUFFICIENT_PERMISSIONS:{message:"Insufficient IAM permissions",solution:"Ensure your IAM user/role has the necessary permissions for CloudFormation and the resources you're deploying"},RESOURCE_LIMIT_EXCEEDED:{message:"AWS service limit exceeded",solution:"Request a service limit increase in the AWS Console, or clean up unused resources"},ROLLBACK_COMPLETE:{message:"Stack creation failed and rolled back",solution:"Check the CloudFormation events to see which resource failed. Fix the issue and try again."},CIRCULAR_DEPENDENCY:{message:"Circular dependency detected in resources",solution:"Review your resource dependencies and remove the circular reference"},INVALID_RESOURCE_NAME:{message:"Resource name contains invalid characters",solution:"Use only alphanumeric characters and hyphens in resource names"},DUPLICATE_RESOURCE:{message:"Duplicate resource name detected",solution:"Ensure all resource names are unique in your configuration"},VPC_CIDR_CONFLICT:{message:"VPC CIDR block conflicts with existing VPC",solution:"Use a different CIDR block that doesn't overlap with existing VPCs"},SUBNET_CIDR_INVALID:{message:"Subnet CIDR block is invalid or outside VPC range",solution:"Ensure subnet CIDR is within the VPC CIDR range and properly sized"},DB_INSTANCE_LIMIT:{message:"RDS instance limit reached",solution:"Delete unused RDS instances or request a limit increase"},INVALID_DB_NAME:{message:"Database name contains invalid characters",solution:"Use only alphanumeric characters and underscores, starting with a letter"},BUCKET_ALREADY_EXISTS:{message:"S3 bucket name already exists globally",solution:"S3 bucket names must be globally unique. Try a different name with your organization prefix"},INVALID_BUCKET_NAME:{message:"S3 bucket name is invalid",solution:"Use lowercase letters, numbers, and hyphens. Must start/end with letter/number. 3-63 characters."},TEMPLATE_TOO_LARGE:{message:"CloudFormation template exceeds size limit",solution:"Split your infrastructure into multiple stacks or use nested stacks"},INVALID_TEMPLATE:{message:"CloudFormation template is invalid",solution:"Validate your template with: cloud config:validate"},PARAMETER_NOT_FOUND:{message:"CloudFormation parameter not found",solution:"Check that all referenced parameters are defined in your template"}};function Ks(e){return js[e]}function ba(e,t){let a=Ks(e);return new fe(a.message,e,a.solution,t)}class te{static verboseMode=!1;static debugMode=!1;static setVerbose(e){this.verboseMode=e}static setDebug(e){this.debugMode=e}static verbose(e,...t){if(this.verboseMode)console.log(`[VERBOSE] ${e}`,...t)}static debug(e,...t){if(this.debugMode)console.log(`[DEBUG] ${e}`,...t)}static info(e,...t){console.log(`ℹ ${e}`,...t)}static warn(e,...t){console.warn(`⚠ ${e}`,...t)}static error(e,t){if(console.error(`✖ ${e}`),t){if(t instanceof fe)console.error(t.toString());else console.error(t.message);if(this.debugMode&&t.stack)console.error(`
|
|
2505
|
+
Stack trace:`),console.error(t.stack)}}static success(e){console.log(`✔ ${e}`)}}function nu(e){if(!e)throw ba("MISSING_CONFIG");if(!e.project)throw new pt("Missing required field: project","Add a project configuration with name, slug, and region",{field:"project"});if(!e.project.name)throw new pt("Missing required field: project.name","Add a project name to your configuration",{field:"project.name"});if(!e.project.slug)throw new pt("Missing required field: project.slug","Add a project slug (lowercase, alphanumeric with hyphens)",{field:"project.slug"});if(!/^[a-z0-9-]+$/.test(e.project.slug))throw new tr("Invalid project slug format","Use only lowercase letters, numbers, and hyphens",{slug:e.project.slug});if(e.project.region){if(!["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","sa-east-1","ca-central-1"].includes(e.project.region))throw ba("INVALID_REGION",{region:e.project.region})}te.success("Configuration validation passed")}function iu(e){let t=[];if(e.environments?.production&&e.infrastructure?.database){let a=e.infrastructure.database;if((a.postgres||a.mysql)&&!a.postgres?.multiAZ&&!a.mysql?.multiAZ)t.push("Production database should use Multi-AZ for high availability")}if(e.infrastructure?.storage){for(let[a,r]of Object.entries(e.infrastructure.storage))if(r.encryption===!1)t.push(`Storage "${a}" is not encrypted - consider enabling encryption for security`)}if(e.infrastructure?.storage){for(let[a,r]of Object.entries(e.infrastructure.storage))if(r.public===!0)t.push(`Storage "${a}" is publicly accessible - ensure this is intentional`)}if(e.infrastructure?.database){let a=e.infrastructure.database;if(a.postgres||a.mysql){let r=a.postgres?.backupRetentionDays||a.mysql?.backupRetentionDays;if(!r||r<7)t.push("Database backup retention is less than 7 days - consider increasing for production")}}if(!e.infrastructure?.monitoring)t.push("No monitoring configured - consider adding CloudWatch alarms");return t}async function su(e="default"){try{te.verbose("Resolving AWS credentials...");let t=await Ms(e);if(!t.accessKeyId||!t.secretAccessKey)throw new Ie("AWS credentials are incomplete","Ensure both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are set");te.verbose("Credentials resolved successfully"),te.debug("Access Key ID:",t.accessKeyId.substring(0,8)+"..."),te.verbose("Testing credentials with GetCallerIdentity...");let a;try{a=await Os(t),te.verbose("Credentials are valid"),te.debug("Account ID:",a)}catch(r){if(r instanceof Error)if(r.message.includes("InvalidClientTokenId"))throw new Ie("Invalid AWS access key ID","Check that your AWS_ACCESS_KEY_ID is correct");else if(r.message.includes("SignatureDoesNotMatch"))throw new Ie("Invalid AWS secret access key","Check that your AWS_SECRET_ACCESS_KEY is correct");else if(r.message.includes("ExpiredToken"))throw new Ie("AWS credentials have expired","Refresh your temporary credentials or use long-term credentials");else throw new Ie(`Failed to validate credentials: ${r.message}`,"Verify your AWS credentials are correct and have the necessary permissions");throw r}return{valid:!0,accountId:a,region:t.region}}catch(t){if(t instanceof Ie)throw t;return{valid:!1,error:t instanceof Error?t.message:"Unknown error"}}}async function ou(e,t){return{allowed:t,denied:[]}}function Hs(e){let t=new Set(["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate","cloudformation:ListStacks"]);if(e.infrastructure){if(e.infrastructure.storage)t.add("s3:CreateBucket"),t.add("s3:DeleteBucket"),t.add("s3:PutBucketPolicy"),t.add("s3:PutBucketVersioning"),t.add("s3:PutBucketEncryption"),t.add("s3:PutObject"),t.add("s3:GetObject");if(e.infrastructure.compute){if(e.infrastructure.compute.server)t.add("ec2:RunInstances"),t.add("ec2:TerminateInstances"),t.add("ec2:DescribeInstances"),t.add("autoscaling:CreateAutoScalingGroup"),t.add("autoscaling:UpdateAutoScalingGroup"),t.add("autoscaling:DeleteAutoScalingGroup"),t.add("elasticloadbalancing:CreateLoadBalancer"),t.add("elasticloadbalancing:DeleteLoadBalancer");if(e.infrastructure.compute.fargate)t.add("ecs:CreateCluster"),t.add("ecs:DeleteCluster"),t.add("ecs:CreateService"),t.add("ecs:UpdateService"),t.add("ecs:DeleteService"),t.add("ecs:RegisterTaskDefinition")}if(e.infrastructure.database){if(e.infrastructure.database.postgres||e.infrastructure.database.mysql)t.add("rds:CreateDBInstance"),t.add("rds:DeleteDBInstance"),t.add("rds:ModifyDBInstance"),t.add("rds:DescribeDBInstances");if(e.infrastructure.database.dynamodb)t.add("dynamodb:CreateTable"),t.add("dynamodb:DeleteTable"),t.add("dynamodb:UpdateTable"),t.add("dynamodb:DescribeTable")}if(e.infrastructure.functions)t.add("lambda:CreateFunction"),t.add("lambda:DeleteFunction"),t.add("lambda:UpdateFunctionCode"),t.add("lambda:UpdateFunctionConfiguration"),t.add("lambda:AddPermission");if(e.infrastructure.cdn)t.add("cloudfront:CreateDistribution"),t.add("cloudfront:UpdateDistribution"),t.add("cloudfront:DeleteDistribution"),t.add("cloudfront:GetDistribution");if(e.infrastructure.network)t.add("ec2:CreateVpc"),t.add("ec2:DeleteVpc"),t.add("ec2:CreateSubnet"),t.add("ec2:DeleteSubnet"),t.add("ec2:CreateInternetGateway"),t.add("ec2:DeleteInternetGateway"),t.add("ec2:CreateNatGateway"),t.add("ec2:DeleteNatGateway"),t.add("ec2:CreateRouteTable"),t.add("ec2:DeleteRouteTable"),t.add("ec2:CreateSecurityGroup"),t.add("ec2:DeleteSecurityGroup")}return t.add("iam:CreateRole"),t.add("iam:DeleteRole"),t.add("iam:AttachRolePolicy"),t.add("iam:DetachRolePolicy"),t.add("iam:PutRolePolicy"),t.add("iam:GetRole"),t.add("iam:PassRole"),Array.from(t).sort()}function cu(e){let t=Hs(e);return JSON.stringify({Version:"2012-10-17",Statement:[{Effect:"Allow",Action:t,Resource:"*"}]},null,2)}var H={ec2:{"Running On-Demand Instances":20,"Elastic IPs":5,VPCs:5,"Internet Gateways":5,"NAT Gateways":5,"Security Groups":500},rds:{"DB Instances":40,"DB Snapshots":100,"DB Parameter Groups":50},lambda:{"Concurrent Executions":1000,"Function Storage":80530636800},s3:{Buckets:100},cloudformation:{Stacks:200,StackSets:100},elasticache:{Nodes:100,Clusters:100},dynamodb:{Tables:256},ecs:{Clusters:1e4,"Services per Cluster":2000}};async function lu(e){let t=[];if(te.verbose("Checking AWS service quotas..."),e.infrastructure?.compute?.server){let r=e.infrastructure.compute.server.autoScaling?.max||1;t.push({service:"EC2",quotaName:"Running On-Demand Instances",currentValue:r,limit:H.ec2["Running On-Demand Instances"],percentage:r/H.ec2["Running On-Demand Instances"]*100,warning:r>H.ec2["Running On-Demand Instances"]*0.8})}if(e.infrastructure?.network?.vpc)t.push({service:"EC2",quotaName:"VPCs",currentValue:1,limit:H.ec2.VPCs,percentage:1/H.ec2.VPCs*100,warning:!1});if(e.infrastructure?.database?.postgres||e.infrastructure?.database?.mysql)t.push({service:"RDS",quotaName:"DB Instances",currentValue:1,limit:H.rds["DB Instances"],percentage:1/H.rds["DB Instances"]*100,warning:!1});if(e.infrastructure?.storage){let r=Object.keys(e.infrastructure.storage).length;t.push({service:"S3",quotaName:"Buckets",currentValue:r,limit:H.s3.Buckets,percentage:r/H.s3.Buckets*100,warning:r>H.s3.Buckets*0.8})}if(e.infrastructure?.functions){let r=0;for(let n of Object.values(e.infrastructure.functions))if(Array.isArray(n))r+=n.length;t.push({service:"Lambda",quotaName:"Functions (estimated)",currentValue:r,limit:1000,percentage:r/1000*100,warning:r>800})}if(e.infrastructure?.database?.dynamodb){let r=e.infrastructure.database.dynamodb.tables?.length||0;t.push({service:"DynamoDB",quotaName:"Tables",currentValue:r,limit:H.dynamodb.Tables,percentage:r/H.dynamodb.Tables*100,warning:r>H.dynamodb.Tables*0.8})}let a=t.filter((r)=>r.warning);if(a.length>0){te.warn("Service quota warnings detected:");for(let r of a)te.warn(` ${r.service} - ${r.quotaName}: ${r.currentValue}/${r.limit} (${r.percentage.toFixed(1)}%)`)}else te.verbose("All service quotas are within limits");return t}function uu(e){if(e.length===0)return"No quotas to check";let t=`Service Quota Usage:
|
|
2506
2506
|
|
|
2507
2507
|
`,a=e.reduce((r,n)=>{if(!r[n.service])r[n.service]=[];return r[n.service].push(n),r},{});for(let[r,n]of Object.entries(a)){t+=`${r}:
|
|
2508
2508
|
`;for(let i of n){let s=i.warning?"⚠":"✓";t+=` ${s} ${i.quotaName}: ${i.currentValue}/${i.limit} (${i.percentage.toFixed(1)}%)
|
|
2509
2509
|
`}t+=`
|
|
2510
|
-
`}return t}function
|
|
2511
|
-
`);return
|
|
2512
|
-
`)}function ku(e,t,a){if(e.deleted.length>0)return!0;for(let r of e.modified){let n=t.Resources[r],i=a.Resources[r];if(n.Type!==i.Type)return!0;let s=to(i.Type);for(let o of s){let c=n.Properties?.[o],l=i.Properties?.[o];if(JSON.stringify(c)!==JSON.stringify(l))return!0}}return!1}function to(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 Mu(e){let t=[],a=[],r=[];t.push(...e.added);for(let n of e.modified)a.push(n);return r.push(...e.deleted),{safe:t,caution:a,dangerous:r}}function Lu(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 xu(e){let t=e.added.length+e.modified.length+e.deleted.length+e.unchanged.length,a=e.added.length+e.modified.length+e.deleted.length,r=t>0?a/t*100:0;return{total:t,added:e.added.length,modified:e.modified.length,deleted:e.deleted.length,unchanged:e.unchanged.length,changePercentage:r}}var Ou={$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 Wu(e){let t=[];if(!e.project)t.push("Missing required field: project");else{if(!e.project.name)t.push("Missing required field: project.name");if(!e.project.slug)t.push("Missing required field: project.slug")}if(e.project?.slug&&!/^[a-z0-9-]+$/.test(e.project.slug))t.push("Invalid project.slug: must contain only lowercase letters, numbers, and hyphens");let a=["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&&!a.includes(e.project.region))t.push(`Invalid region: ${e.project.region}. Must be one of: ${a.join(", ")}`);if(e.mode&&!["server","serverless"].includes(e.mode))t.push("Invalid mode: must be one of server or serverless");return{valid:t.length===0,errors:t}}var or={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 $t(){return or}function _u(){return or.enabled}function Bu(e){let t=$t();if(!t.enabled)return"";switch(e.toLowerCase()){case"dynamodb":return t.dynamodbEndpoint;case"s3":return t.s3Endpoint;case"localstack":case"cloudformation":case"lambda":case"apigateway":case"sns":case"sqs":case"cloudwatch":case"iam":case"sts":return t.localstackEndpoint;default:return t.localstackEndpoint}}function Uu(){let e=$t();return{accessKeyId:e.awsAccessKeyId,secretAccessKey:e.awsSecretAccessKey,region:e.awsRegion}}function Gu(){let e=$t();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 cr{stacks=new Map;stackEvents=new Map;async createStack(e){let t=`arn:aws:cloudformation:${e.region||"us-east-1"}:123456789012:stack/${e.StackName}/${Date.now()}`;return this.stacks.set(e.StackName,{StackId:t,StackName:e.StackName,StackStatus:"CREATE_IN_PROGRESS",CreationTime:new Date().toISOString(),TemplateBody:e.TemplateBody,Parameters:e.Parameters||[]}),this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_IN_PROGRESS"}),setTimeout(()=>{let a=this.stacks.get(e.StackName);if(a)a.StackStatus="CREATE_COMPLETE",this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_COMPLETE"})},100),{StackId:t}}async updateStack(e){let t=this.stacks.get(e.StackName);if(!t)throw Error(`Stack ${e.StackName} does not exist`);return t.StackStatus="UPDATE_IN_PROGRESS",t.TemplateBody=e.TemplateBody||t.TemplateBody,this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_IN_PROGRESS"}),setTimeout(()=>{t.StackStatus="UPDATE_COMPLETE",this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_COMPLETE"})},100),{StackId:t.StackId}}async deleteStack(e){let t=this.stacks.get(e.StackName);if(!t)throw Error(`Stack ${e.StackName} does not exist`);t.StackStatus="DELETE_IN_PROGRESS",this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_IN_PROGRESS"}),setTimeout(()=>{this.stacks.delete(e.StackName),this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_COMPLETE"})},100)}async describeStacks(e){if(e.StackName){let t=this.stacks.get(e.StackName);if(!t)throw Error(`Stack ${e.StackName} does not exist`);return{Stacks:[t]}}return{Stacks:Array.from(this.stacks.values())}}async describeStackEvents(e){return{StackEvents:this.stackEvents.get(e.StackName)||[]}}addEvent(e,t){if(!this.stackEvents.has(e))this.stackEvents.set(e,[]);this.stackEvents.get(e).unshift(t)}reset(){this.stacks.clear(),this.stackEvents.clear()}}class lr{buckets=new Map;async createBucket(e){return this.buckets.set(e.Bucket,new Map),{Location:`/${e.Bucket}`}}async deleteBucket(e){this.buckets.delete(e.Bucket)}async putObject(e){let t=this.buckets.get(e.Bucket);if(!t)t=new Map,this.buckets.set(e.Bucket,t);return t.set(e.Key,Buffer.from(e.Body||"")),{ETag:`"${Date.now()}"`}}async getObject(e){let t=this.buckets.get(e.Bucket);if(!t)throw Error(`Bucket ${e.Bucket} does not exist`);let a=t.get(e.Key);if(!a)throw Error(`Object ${e.Key} does not exist`);return{Body:a,ContentLength:a.length}}async deleteObject(e){let t=this.buckets.get(e.Bucket);if(t)t.delete(e.Key)}async listObjects(e){let t=this.buckets.get(e.Bucket);if(!t)throw Error(`Bucket ${e.Bucket} does not exist`);return{Contents:Array.from(t.keys()).map((a)=>({Key:a,Size:t.get(a).length,LastModified:new Date().toISOString()}))}}reset(){this.buckets.clear()}}class ur{tables=new Map;data=new Map;async createTable(e){return this.tables.set(e.TableName,{TableName:e.TableName,KeySchema:e.KeySchema,AttributeDefinitions:e.AttributeDefinitions,TableStatus:"ACTIVE",CreationDateTime:new Date().toISOString()}),this.data.set(e.TableName,new Map),{TableDescription:this.tables.get(e.TableName)}}async deleteTable(e){this.tables.delete(e.TableName),this.data.delete(e.TableName)}async putItem(e){let t=this.data.get(e.TableName);if(!t)t=new Map,this.data.set(e.TableName,t);let a=JSON.stringify(e.Item);t.set(a,e.Item)}async getItem(e){let t=this.data.get(e.TableName);if(!t)return{};let a=JSON.stringify(e.Key),r=t.get(a);return r?{Item:r}:{}}async deleteItem(e){let t=this.data.get(e.TableName);if(t){let a=JSON.stringify(e.Key);t.delete(a)}}async scan(e){let t=this.data.get(e.TableName);if(!t)return{Items:[]};return{Items:Array.from(t.values())}}reset(){this.tables.clear(),this.data.clear()}}function Vu(e){return{cloudformation:new cr,s3:new lr,dynamodb:new ur}}class dr{environments=new Map;async createPreviewEnvironment(e){let{branch:t,pr:a,commitSha:r,ttl:n=24,baseConfig:i,region:s="us-east-1"}=e,o=this.generatePreviewId(t,a,r),c=this.generatePreviewName(t,a),l=`preview-${c}`,u=new Date,m=new Date(u.getTime()+n*60*60*1000),p={id:o,name:c,branch:t,pr:a,commitSha:r,createdAt:u,expiresAt:m,status:"creating",stackName:l,region:s,resources:[]};this.environments.set(o,p);try{let g=this.createPreviewConfig(i,c);return p.status="active",p.url=`https://${c}.preview.example.com`,p}catch(g){throw p.status="failed",g}}async destroyPreviewEnvironment(e){let t=this.environments.get(e);if(!t)throw Error(`Preview environment ${e} not found`);t.status="destroying";try{t.status="destroyed",this.environments.delete(e)}catch(a){throw Error(`Failed to destroy preview environment: ${a}`)}}getPreviewEnvironment(e){return this.environments.get(e)}getPreviewEnvironmentByBranch(e){return Array.from(this.environments.values()).find((t)=>t.branch===e)}getPreviewEnvironmentByPR(e){return Array.from(this.environments.values()).find((t)=>t.pr===e)}listPreviewEnvironments(){return Array.from(this.environments.values())}listActivePreviewEnvironments(){return this.listPreviewEnvironments().filter((e)=>e.status==="active")}async cleanupExpiredEnvironments(e={}){let{maxAge:t,keepCount:a,dryRun:r=!1}=e,n=[],i=[],s=new Date,o=this.listPreviewEnvironments().sort((c,l)=>l.createdAt.getTime()-c.createdAt.getTime());for(let c=0;c<o.length;c++){let l=o[c];if(l.status!=="active")continue;let u=!1;if(l.expiresAt<s)u=!0;if(t){if((s.getTime()-l.createdAt.getTime())/3600000>t)u=!0}if(a&&c>=a)u=!0;if(u)if(r)n.push(l.id);else try{await this.destroyPreviewEnvironment(l.id),n.push(l.id)}catch(m){i.push(l.id)}}return{destroyed:n,failed:i}}async updatePreviewEnvironment(e,t){let a=this.environments.get(e);if(!a)throw Error(`Preview environment ${e} not found`);a.commitSha=t,a.status="creating";try{return a.status="active",a}catch(r){throw a.status="failed",r}}async getPreviewEnvironmentsCost(){let e={},t=0;for(let a of this.environments.values())e[a.id]=0,t+=0;return{total:t,byEnvironment:e}}generatePreviewId(e,t,a){let r=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase(),n=a?.substring(0,7)||Date.now().toString();return t?`pr-${t}-${n}`:`${r}-${n}`}generatePreviewName(e,t){let a=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase();return t?`pr-${t}`:a}createPreviewConfig(e,t){return{...e,project:{...e.project,name:`${e.project.name} Preview (${t})`,slug:`${e.project.slug}-preview-${t}`}}}}var Fu=new dr;function ju(e={}){let{workflowName:t="Preview Environment",trigger:a="pull_request",branches:r=["main","develop"],awsRegion:n="us-east-1",awsRole:i,configFile:s="cloud.config.ts",ttl:o=24}=e;return`name: ${t}
|
|
2510
|
+
`}return t}function du(e){let t=[];for(let a of e)if(a.percentage>=100)t.push(`Request quota increase for ${a.service} - ${a.quotaName} (currently ${a.limit})`);else if(a.warning)t.push(`Consider requesting quota increase for ${a.service} - ${a.quotaName} (${a.percentage.toFixed(1)}% used)`);return t}class rr{cacheDir;ttl;constructor(e,t={}){this.cacheDir=e,this.ttl=t.ttl||86400000}ensureCacheDir(){if(!lt(this.cacheDir))qs(this.cacheDir,{recursive:!0})}getCachePath(e){let t=ar("sha256").update(e).digest("hex");return xt(this.cacheDir,`${t}.json`)}get(e){let t=this.getCachePath(e);if(!lt(t))return;try{let a=Ca(t,"utf-8"),r=JSON.parse(a);if(Date.now()-r.timestamp>this.ttl){He(t);return}return r.value}catch{He(t);return}}set(e,t,a){this.ensureCacheDir();let r=this.getCachePath(e),n={value:t,timestamp:Date.now(),hash:a};zs(r,JSON.stringify(n),"utf-8")}has(e){return this.get(e)!==void 0}clear(){if(!lt(this.cacheDir))return;let e=Aa(this.cacheDir);for(let t of e)He(xt(this.cacheDir,t))}prune(){if(!lt(this.cacheDir))return;let e=Aa(this.cacheDir),t=Date.now();for(let a of e){let r=xt(this.cacheDir,a);try{let n=Ca(r,"utf-8"),i=JSON.parse(n);if(t-i.timestamp>this.ttl)He(r)}catch{He(r)}}}}class nr{cache;constructor(e=Zn("cache","templates")){this.cache=new rr(e,{ttl:86400000})}getTemplate(e){return this.cache.get(`template:${e}`)}setTemplate(e,t){let a=this.hashTemplate(t);this.cache.set(`template:${e}`,t,a)}hasChanged(e,t){let a=this.cache.get(`template:${e}`);if(!a)return!0;let r=this.hashTemplate(a),n=this.hashTemplate(t);return r!==n}hashTemplate(e){return ar("sha256").update(e).digest("hex")}clear(){this.cache.clear()}prune(){this.cache.prune()}}var Ot=null;function hu(){if(!Ot)Ot=new nr;return Ot}async function ir(e,t={}){let a=t.algorithm||"sha256",r=t.chunkSize||65536;return new Promise((n,i)=>{let s=Qt(a),o=Qs(e,{highWaterMark:r});o.on("data",(c)=>s.update(c)),o.on("end",()=>n(s.digest("hex"))),o.on("error",i)})}function sr(e,t="sha256"){return Qt(t).update(e).digest("hex")}function bu(e,t="sha256"){return Qt(t).update(e).digest("hex")}async function Au(e,t={}){let a=t.ignorePatterns||["node_modules",".git","dist","build",Et()],r=[];async function n(i){let s=Js(i,{withFileTypes:!0});for(let o of s){let c=Ys(i,o.name),l=Zs(e,c);if(a.some((u)=>l.includes(u)))continue;if(o.isDirectory())await n(c);else if(o.isFile()){let u=At(c),m=await ir(c,t);r.push({path:l,hash:m,size:u.size,mtime:u.mtimeMs})}}}return await n(e),r}function Cu(e){let t=[...e].sort((a,r)=>a.path.localeCompare(r.path)).map((a)=>`${a.path}:${a.hash}`).join(`
|
|
2511
|
+
`);return sr(t)}function Tu(e){let t=At(e);return sr(`${e}:${t.size}:${t.mtimeMs}`)}function vu(e,t){let a=new Map(e.map((o)=>[o.path,o])),r=new Map(t.map((o)=>[o.path,o])),n=[],i=[],s=[];for(let[o,c]of r){let l=a.get(o);if(!l)n.push(c);else if(l.hash!==c.hash)i.push(c)}for(let[o,c]of a)if(!r.has(o))s.push(c);return{added:n,modified:i,deleted:s}}class Xs{cache;constructor(){this.cache=new Map}get(e){let t=At(e),a=this.cache.get(e);if(a&&a.mtime===t.mtimeMs&&a.size===t.size)return a.hash;return}set(e,t){let a=At(e);this.cache.set(e,{hash:t,mtime:a.mtimeMs,size:a.size})}async getOrCompute(e,t={}){let a=this.get(e);if(a)return a;let r=await ir(e,t);return this.set(e,r),r}clear(){this.cache.clear()}}async function Jt(e,t={}){let a=t.concurrency||5,r=t.stopOnError??!0,n=[],i=[],s=Date.now(),o=[...e],c=[];async function l(p,g){try{let h=await p();n[g]=h}catch(h){let y=h instanceof Error?h:Error(String(h));if(i.push(y),r)throw o.length=0,y}}let u=0;while(o.length>0||c.length>0){while(c.length<a&&o.length>0){let p=o.shift(),g=u++,h=l(p,g);c.push(h)}if(c.length>0){await Promise.race(c);for(let p=c.length-1;p>=0;p--)if(await Promise.race([c[p].then(()=>!0),Promise.resolve(!1)]))c.splice(p,1)}if(r&&i.length>0)break}let m=Date.now()-s;return{results:n.filter((p)=>p!==void 0),errors:i,duration:m}}async function wu(e,t,a={}){let r=e.map((n)=>()=>t(n));return Jt(r,a)}async function Eu(e,t,a=5){let r=e.map((i,s)=>()=>t(i,s)),n=await Jt(r,{concurrency:a,stopOnError:!1});if(n.errors.length>0)throw AggregateError(n.errors,"Parallel map failed");return n.results}async function Pu(e,t={}){let a=t.retries||3,r=t.retryDelay||1000,n=e.map((i)=>async()=>{let s;for(let o=0;o<=a;o++)try{return await i()}catch(c){if(s=c instanceof Error?c:Error(String(c)),o<a)await or(r*(o+1))}throw s});return Jt(n,t)}async function Iu(e){let t=[];for(let a of e){let r=await a();t.push(r)}return t}function or(e){return new Promise((t)=>setTimeout(t,e))}async function Ru(e,t,a="Operation timed out"){return Promise.race([e(),new Promise((r,n)=>setTimeout(()=>n(Error(a)),t))])}class eo{maxConcurrent;minInterval;queue=[];running=0;lastExecution=0;constructor(e=5,t=100){this.maxConcurrent=e,this.minInterval=t}async execute(e){await this.waitForSlot(),this.running++,this.lastExecution=Date.now();try{return await e()}finally{this.running--,this.processQueue()}}waitForSlot(){if(this.running<this.maxConcurrent){let e=Date.now()-this.lastExecution;if(e>=this.minInterval)return Promise.resolve();return or(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 to(e,t){let a=[];for(let r=0;r<e.length;r+=t)a.push(e.slice(r,r+t));return a}async function Nu(e,t,a){let r=to(e,t),n=[];for(let i of r){let s=await a(i);n.push(...s)}return n}function Du(e,t){let a=[],r=[],n=[],i=[],s=e.Resources||{},o=t.Resources||{},c=new Set(Object.keys(s)),l=new Set(Object.keys(o));for(let p of l)if(!c.has(p))a.push(p);for(let p of c)if(!l.has(p))n.push(p);for(let p of l)if(c.has(p)){let g=s[p],h=o[p];if(JSON.stringify(g)!==JSON.stringify(h))r.push(p);else i.push(p)}let u=JSON.stringify(e.Parameters||{})!==JSON.stringify(t.Parameters||{}),m=JSON.stringify(e.Outputs||{})!==JSON.stringify(t.Outputs||{});return{added:a,modified:r,deleted:n,unchanged:i,parametersChanged:u,outputsChanged:m,hasChanges:a.length>0||r.length>0||n.length>0||u||m}}function ku(e){let t=[];if(!e.hasChanges)return"No changes detected";if(e.added.length>0){t.push(`Added resources (${e.added.length}):`);for(let a of e.added)t.push(` + ${a}`)}if(e.modified.length>0){t.push(`Modified resources (${e.modified.length}):`);for(let a of e.modified)t.push(` ~ ${a}`)}if(e.deleted.length>0){t.push(`Deleted resources (${e.deleted.length}):`);for(let a of e.deleted)t.push(` - ${a}`)}if(e.parametersChanged)t.push("Parameters changed");if(e.outputsChanged)t.push("Outputs changed");return t.join(`
|
|
2512
|
+
`)}function $u(e,t,a){if(e.deleted.length>0)return!0;for(let r of e.modified){let n=t.Resources[r],i=a.Resources[r];if(n.Type!==i.Type)return!0;let s=ao(i.Type);for(let o of s){let c=n.Properties?.[o],l=i.Properties?.[o];if(JSON.stringify(c)!==JSON.stringify(l))return!0}}return!1}function ao(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 Lu(e){let t=[],a=[],r=[];t.push(...e.added);for(let n of e.modified)a.push(n);return r.push(...e.deleted),{safe:t,caution:a,dangerous:r}}function Mu(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 xu(e){let t=e.added.length+e.modified.length+e.deleted.length+e.unchanged.length,a=e.added.length+e.modified.length+e.deleted.length,r=t>0?a/t*100:0;return{total:t,added:e.added.length,modified:e.modified.length,deleted:e.deleted.length,unchanged:e.unchanged.length,changePercentage:r}}var Ou={$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 Bu(e){let t=[];if(!e.project)t.push("Missing required field: project");else{if(!e.project.name)t.push("Missing required field: project.name");if(!e.project.slug)t.push("Missing required field: project.slug")}if(e.project?.slug&&!/^[a-z0-9-]+$/.test(e.project.slug))t.push("Invalid project.slug: must contain only lowercase letters, numbers, and hyphens");let a=["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&&!a.includes(e.project.region))t.push(`Invalid region: ${e.project.region}. Must be one of: ${a.join(", ")}`);if(e.mode&&!["server","serverless"].includes(e.mode))t.push("Invalid mode: must be one of server or serverless");return{valid:t.length===0,errors:t}}var cr={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 Yt(){return cr}function _u(){return cr.enabled}function Wu(e){let t=Yt();if(!t.enabled)return"";switch(e.toLowerCase()){case"dynamodb":return t.dynamodbEndpoint;case"s3":return t.s3Endpoint;case"localstack":case"cloudformation":case"lambda":case"apigateway":case"sns":case"sqs":case"cloudwatch":case"iam":case"sts":return t.localstackEndpoint;default:return t.localstackEndpoint}}function Gu(){let e=Yt();return{accessKeyId:e.awsAccessKeyId,secretAccessKey:e.awsSecretAccessKey,region:e.awsRegion}}function Fu(){let e=Yt();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 lr{stacks=new Map;stackEvents=new Map;async createStack(e){let t=`arn:aws:cloudformation:${e.region||"us-east-1"}:123456789012:stack/${e.StackName}/${Date.now()}`;return this.stacks.set(e.StackName,{StackId:t,StackName:e.StackName,StackStatus:"CREATE_IN_PROGRESS",CreationTime:new Date().toISOString(),TemplateBody:e.TemplateBody,Parameters:e.Parameters||[]}),this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_IN_PROGRESS"}),setTimeout(()=>{let a=this.stacks.get(e.StackName);if(a)a.StackStatus="CREATE_COMPLETE",this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_COMPLETE"})},100),{StackId:t}}async updateStack(e){let t=this.stacks.get(e.StackName);if(!t)throw Error(`Stack ${e.StackName} does not exist`);return t.StackStatus="UPDATE_IN_PROGRESS",t.TemplateBody=e.TemplateBody||t.TemplateBody,this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_IN_PROGRESS"}),setTimeout(()=>{t.StackStatus="UPDATE_COMPLETE",this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_COMPLETE"})},100),{StackId:t.StackId}}async deleteStack(e){let t=this.stacks.get(e.StackName);if(!t)throw Error(`Stack ${e.StackName} does not exist`);t.StackStatus="DELETE_IN_PROGRESS",this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_IN_PROGRESS"}),setTimeout(()=>{this.stacks.delete(e.StackName),this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_COMPLETE"})},100)}async describeStacks(e){if(e.StackName){let t=this.stacks.get(e.StackName);if(!t)throw Error(`Stack ${e.StackName} does not exist`);return{Stacks:[t]}}return{Stacks:Array.from(this.stacks.values())}}async describeStackEvents(e){return{StackEvents:this.stackEvents.get(e.StackName)||[]}}addEvent(e,t){if(!this.stackEvents.has(e))this.stackEvents.set(e,[]);this.stackEvents.get(e).unshift(t)}reset(){this.stacks.clear(),this.stackEvents.clear()}}class ur{buckets=new Map;async createBucket(e){return this.buckets.set(e.Bucket,new Map),{Location:`/${e.Bucket}`}}async deleteBucket(e){this.buckets.delete(e.Bucket)}async putObject(e){let t=this.buckets.get(e.Bucket);if(!t)t=new Map,this.buckets.set(e.Bucket,t);return t.set(e.Key,Buffer.from(e.Body||"")),{ETag:`"${Date.now()}"`}}async getObject(e){let t=this.buckets.get(e.Bucket);if(!t)throw Error(`Bucket ${e.Bucket} does not exist`);let a=t.get(e.Key);if(!a)throw Error(`Object ${e.Key} does not exist`);return{Body:a,ContentLength:a.length}}async deleteObject(e){let t=this.buckets.get(e.Bucket);if(t)t.delete(e.Key)}async listObjects(e){let t=this.buckets.get(e.Bucket);if(!t)throw Error(`Bucket ${e.Bucket} does not exist`);return{Contents:Array.from(t.keys()).map((a)=>({Key:a,Size:t.get(a).length,LastModified:new Date().toISOString()}))}}reset(){this.buckets.clear()}}class dr{tables=new Map;data=new Map;async createTable(e){return this.tables.set(e.TableName,{TableName:e.TableName,KeySchema:e.KeySchema,AttributeDefinitions:e.AttributeDefinitions,TableStatus:"ACTIVE",CreationDateTime:new Date().toISOString()}),this.data.set(e.TableName,new Map),{TableDescription:this.tables.get(e.TableName)}}async deleteTable(e){this.tables.delete(e.TableName),this.data.delete(e.TableName)}async putItem(e){let t=this.data.get(e.TableName);if(!t)t=new Map,this.data.set(e.TableName,t);let a=JSON.stringify(e.Item);t.set(a,e.Item)}async getItem(e){let t=this.data.get(e.TableName);if(!t)return{};let a=JSON.stringify(e.Key),r=t.get(a);return r?{Item:r}:{}}async deleteItem(e){let t=this.data.get(e.TableName);if(t){let a=JSON.stringify(e.Key);t.delete(a)}}async scan(e){let t=this.data.get(e.TableName);if(!t)return{Items:[]};return{Items:Array.from(t.values())}}reset(){this.tables.clear(),this.data.clear()}}function Vu(e){return{cloudformation:new lr,s3:new ur,dynamodb:new dr}}class mr{environments=new Map;async createPreviewEnvironment(e){let{branch:t,pr:a,commitSha:r,ttl:n=24,baseConfig:i,region:s="us-east-1"}=e,o=this.generatePreviewId(t,a,r),c=this.generatePreviewName(t,a),l=`preview-${c}`,u=new Date,m=new Date(u.getTime()+n*60*60*1000),p={id:o,name:c,branch:t,pr:a,commitSha:r,createdAt:u,expiresAt:m,status:"creating",stackName:l,region:s,resources:[]};this.environments.set(o,p);try{let g=this.createPreviewConfig(i,c);return p.status="active",p.url=`https://${c}.preview.example.com`,p}catch(g){throw p.status="failed",g}}async destroyPreviewEnvironment(e){let t=this.environments.get(e);if(!t)throw Error(`Preview environment ${e} not found`);t.status="destroying";try{t.status="destroyed",this.environments.delete(e)}catch(a){throw Error(`Failed to destroy preview environment: ${a}`)}}getPreviewEnvironment(e){return this.environments.get(e)}getPreviewEnvironmentByBranch(e){return Array.from(this.environments.values()).find((t)=>t.branch===e)}getPreviewEnvironmentByPR(e){return Array.from(this.environments.values()).find((t)=>t.pr===e)}listPreviewEnvironments(){return Array.from(this.environments.values())}listActivePreviewEnvironments(){return this.listPreviewEnvironments().filter((e)=>e.status==="active")}async cleanupExpiredEnvironments(e={}){let{maxAge:t,keepCount:a,dryRun:r=!1}=e,n=[],i=[],s=new Date,o=this.listPreviewEnvironments().sort((c,l)=>l.createdAt.getTime()-c.createdAt.getTime());for(let c=0;c<o.length;c++){let l=o[c];if(l.status!=="active")continue;let u=!1;if(l.expiresAt<s)u=!0;if(t){if((s.getTime()-l.createdAt.getTime())/3600000>t)u=!0}if(a&&c>=a)u=!0;if(u)if(r)n.push(l.id);else try{await this.destroyPreviewEnvironment(l.id),n.push(l.id)}catch(m){i.push(l.id)}}return{destroyed:n,failed:i}}async updatePreviewEnvironment(e,t){let a=this.environments.get(e);if(!a)throw Error(`Preview environment ${e} not found`);a.commitSha=t,a.status="creating";try{return a.status="active",a}catch(r){throw a.status="failed",r}}async getPreviewEnvironmentsCost(){let e={},t=0;for(let a of this.environments.values())e[a.id]=0,t+=0;return{total:t,byEnvironment:e}}generatePreviewId(e,t,a){let r=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase(),n=a?.substring(0,7)||Date.now().toString();return t?`pr-${t}-${n}`:`${r}-${n}`}generatePreviewName(e,t){let a=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase();return t?`pr-${t}`:a}createPreviewConfig(e,t){return{...e,project:{...e.project,name:`${e.project.name} Preview (${t})`,slug:`${e.project.slug}-preview-${t}`}}}}var Uu=new mr;function ju(e={}){let{workflowName:t="Preview Environment",trigger:a="pull_request",branches:r=["main","develop"],awsRegion:n="us-east-1",awsRole:i,configFile:s="cloud.config.ts",ttl:o=24}=e;return`name: ${t}
|
|
2513
2513
|
|
|
2514
2514
|
on:
|
|
2515
2515
|
${a}:
|
|
@@ -2737,15 +2737,15 @@ jobs:
|
|
|
2737
2737
|
curl -X POST -H 'Content-type: application/json' \\
|
|
2738
2738
|
--data '{"text":"Preview Environment Cost Report\\n\${{ steps.cost.outputs.cost_json }}"}' \\
|
|
2739
2739
|
$SLACK_WEBHOOK_URL`:'run: |\n echo "${{ steps.cost.outputs.cost_json }}"'}
|
|
2740
|
-
`}class
|
|
2741
|
-
`)}function
|
|
2742
|
-
`)}function
|
|
2743
|
-
`)}function
|
|
2744
|
-
`)}class
|
|
2740
|
+
`}class pr{channels=[];addChannel(e){this.channels.push(e)}removeChannel(e){this.channels=this.channels.filter((t)=>t.type!==e)}async notify(e){let t=this.channels.map((a)=>this.sendToChannel(a,e));await Promise.allSettled(t)}async sendToChannel(e,t){switch(e.type){case"slack":await this.sendToSlack(e.config,t);break;case"discord":await this.sendToDiscord(e.config,t);break;case"email":await this.sendToEmail(e.config,t);break;case"webhook":await this.sendToWebhook(e.config,t);break}}async sendToSlack(e,t){let a=this.formatSlackMessage(t,e),r=await fetch(e.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!r.ok)throw Error(`Failed to send Slack notification: ${r.statusText}`)}formatSlackMessage(e,t){let{environment:a,type:r}=e,n={created:":rocket:",updated:":arrows_counterclockwise:",destroyed:":wastebasket:",failed:":x:",expired:":hourglass_flowing_sand:"}[r],i={created:"#36a64f",updated:"#2196F3",destroyed:"#808080",failed:"#f44336",expired:"#ff9800"}[r],s={created:"Preview Environment Created",updated:"Preview Environment Updated",destroyed:"Preview Environment Destroyed",failed:"Preview Environment Failed",expired:"Preview Environment Expired"}[r];return{username:t.username||"ts-cloud",icon_emoji:t.iconEmoji||":cloud:",channel:t.channel,attachments:[{color:i,title:`${n} ${s}`,fields:[{title:"Environment",value:a.name,short:!0},{title:"Branch",value:a.branch,short:!0},...a.pr?[{title:"PR",value:`#${a.pr}`,short:!0}]:[],{title:"Commit",value:a.commitSha.substring(0,7),short:!0},...a.url?[{title:"URL",value:a.url,short:!1}]:[],...r==="created"?[{title:"Expires",value:a.expiresAt.toLocaleString(),short:!0}]:[]],footer:"ts-cloud Preview Environments",ts:Math.floor(e.timestamp.getTime()/1000)}]}}async sendToDiscord(e,t){let a=this.formatDiscordMessage(t,e),r=await fetch(e.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!r.ok)throw Error(`Failed to send Discord notification: ${r.statusText}`)}formatDiscordMessage(e,t){let{environment:a,type:r}=e,n={created:":rocket:",updated:":arrows_counterclockwise:",destroyed:":wastebasket:",failed:":x:",expired:":hourglass:"}[r],i={created:3581519,updated:2201331,destroyed:8421504,failed:16007990,expired:16750592}[r],s={created:"Preview Environment Created",updated:"Preview Environment Updated",destroyed:"Preview Environment Destroyed",failed:"Preview Environment Failed",expired:"Preview Environment Expired"}[r];return{username:t.username||"ts-cloud",avatar_url:t.avatarUrl,embeds:[{title:`${n} ${s}`,color:i,fields:[{name:"Environment",value:a.name,inline:!0},{name:"Branch",value:a.branch,inline:!0},...a.pr?[{name:"PR",value:`#${a.pr}`,inline:!0}]:[],{name:"Commit",value:`\`${a.commitSha.substring(0,7)}\``,inline:!0},...a.url?[{name:"URL",value:a.url,inline:!1}]:[]],timestamp:e.timestamp.toISOString(),footer:{text:"ts-cloud Preview Environments"}}]}}async sendToEmail(e,t){console.log(`Email notification would be sent to ${e.to.join(", ")}`)}async sendToWebhook(e,t){let a=await fetch(e.url,{method:e.method||"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify({event:t.type,environment:t.environment,timestamp:t.timestamp.toISOString(),metadata:t.metadata})});if(!a.ok)throw Error(`Failed to send webhook notification: ${a.statusText}`)}}var qu=new pr;function zu(e){let{columns:t,data:a,border:r=!0,header:n=!0,compact:i=!1,maxWidth:s}=e;if(a.length===0)return"No data to display";let o=t.map((l)=>{let u=l.label.length,m=Math.max(...a.map((g)=>(l.formatter?l.formatter(g[l.key]):String(g[l.key]||"")).length)),p=l.width||Math.max(u,m);if(s&&p>s)p=s;return p}),c=[];if(r)c.push(Bt(o,"top",i));if(n){if(c.push(Ta(t.map((l)=>l.label),o,t.map((l)=>l.align||"left"),r)),r)c.push(Bt(o,"middle",i))}for(let l of a){let u=t.map((m)=>{let p=m.formatter?m.formatter(l[m.key]):String(l[m.key]||"");return no(p,o[t.indexOf(m)])});c.push(Ta(u,o,t.map((m)=>m.align||"left"),r))}if(r)c.push(Bt(o,"bottom",i));return c.join(`
|
|
2741
|
+
`)}function Ta(e,t,a,r){let n=e.map((i,s)=>{let o=t[s],c=a[s];return ro(i,o,c)});if(r)return`│ ${n.join(" │ ")} │`;return n.join(" ")}function Bt(e,t,a){let r=t==="top"?"┌":t==="middle"?"├":"└",n=t==="top"?"┐":t==="middle"?"┤":"┘",i=t==="top"?"┬":t==="middle"?"┼":"┴",s="─";if(a)return r+e.map((o)=>"─".repeat(o+2)).join(i)+n;return r+e.map((o)=>"─".repeat(o+2)).join(i)+n}function ro(e,t,a){let r=gr(e).length;if(r>=t)return e;let n=t-r;switch(a){case"right":return" ".repeat(n)+e;case"center":{let i=Math.floor(n/2),s=n-i;return" ".repeat(i)+e+" ".repeat(s)}default:return e+" ".repeat(n)}}function no(e,t){if(gr(e).length<=t)return e;return e.substring(0,t-1)+"…"}function gr(e){return e.replace(/\x1B\[[0-9;]*m/g,"")}function Qu(e,t={}){let{indent:a=" ",showMetadata:r=!1}=t,n=[];function i(s,o,c){let l=o+(c?"└─ ":"├─ ")+s.label;if(n.push(l),r&&s.metadata){let u=o+(c?" ":"│ ");for(let[m,p]of Object.entries(s.metadata))n.push(`${u}${m}: ${p}`)}if(s.children&&s.children.length>0){let u=o+(c?" ":"│ ");s.children.forEach((m,p)=>{i(m,u,p===s.children.length-1)})}}return e.forEach((s,o)=>{i(s,"",o===e.length-1)}),n.join(`
|
|
2742
|
+
`)}function Ju(e){let{total:t,current:a,width:r=40,format:n=":bar :percent :current/:total",complete:i="█",incomplete:s="░"}=e,o=Math.min(100,Math.max(0,a/t*100)),c=Math.floor(r*a/t),l=r-c,u=i.repeat(c)+s.repeat(l);return n.replace(":bar",u).replace(":percent",`${o.toFixed(0)}%`).replace(":current",String(a)).replace(":total",String(t))}function Yu(e,t=2){if(e===0)return"0 Bytes";let a=1024,r=t<0?0:t,n=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],i=Math.floor(Math.log(e)/Math.log(a));return`${Number.parseFloat((e/Math.pow(a,i)).toFixed(r))} ${n[i]}`}function Zu(e){if(e<1000)return`${e}ms`;let t=Math.floor(e/1000);if(t<60)return`${t}s`;let a=Math.floor(t/60),r=t%60;if(a<60)return r>0?`${a}m ${r}s`:`${a}m`;let n=Math.floor(a/60),i=a%60;if(n<24)return i>0?`${n}h ${i}m`:`${n}h`;let s=Math.floor(n/24),o=n%24;return o>0?`${s}d ${o}h`:`${s}d`}function Xu(e,t="•"){return e.map((a)=>`${t} ${a}`).join(`
|
|
2743
|
+
`)}function ed(e,t={}){let{indent:a="",separator:r=": "}=t,n=Math.max(...Object.keys(e).map((i)=>i.length));return Object.entries(e).map(([i,s])=>{let o=i.padEnd(n);return`${a}${o}${r}${s}`}).join(`
|
|
2744
|
+
`)}class io{total;current=0;width;format;message;showETA;showPercentage;showCounter;startTime=Date.now();lastUpdate=0;constructor(e){this.total=e.total,this.current=e.current||0,this.width=e.width||40,this.format=e.format||":message :bar :percent :eta",this.message=e.message||"Progress",this.showETA=e.showETA!==!1,this.showPercentage=e.showPercentage!==!1,this.showCounter=e.showCounter!==!1}tick(e=1){this.current=Math.min(this.total,this.current+e),this.lastUpdate=Date.now()}update(e){this.current=Math.min(this.total,Math.max(0,e)),this.lastUpdate=Date.now()}setMessage(e){this.message=e}getPercentage(){return Math.min(100,this.current/this.total*100)}getETA(){if(this.current===0)return 0;let e=Date.now()-this.startTime,t=this.current/e,a=this.total-this.current;return Math.round(a/t)}getETAFormatted(){if(this.current===0)return"calculating...";if(this.current===this.total)return"complete";let e=this.getETA();if(e<1000)return"< 1s";if(e<60000)return`${Math.round(e/1000)}s`;let t=Math.floor(e/60000);if(t<60)return`${t}m`;let a=Math.floor(t/60),r=t%60;if(a<24)return r>0?`${a}h ${r}m`:`${a}h`;let n=Math.floor(a/24),i=a%24;return i>0?`${n}d ${i}h`:`${n}d`}render(){let e=this.getPercentage(),t=Math.floor(this.width*this.current/this.total),a=this.width-t,r="█".repeat(t)+"░".repeat(a),n=`${e.toFixed(1)}%`,i=`${this.current}/${this.total}`,s=this.showETA?`ETA: ${this.getETAFormatted()}`:"",o=this.format.replace(":message",this.message).replace(":bar",r).replace(":percent",this.showPercentage?n:"").replace(":counter",this.showCounter?i:"").replace(":eta",s).replace(":current",String(this.current)).replace(":total",String(this.total));return o=o.replace(/\s+/g," ").trim(),o}isComplete(){return this.current>=this.total}}class so{steps;currentStepIndex=0;constructor(e){this.steps=e.map((t)=>({name:t,status:"pending"}))}startStep(e,t){if(e>=0&&e<this.steps.length)this.steps[e].status="active",this.steps[e].message=t,this.currentStepIndex=e}completeStep(e){if(this.currentStepIndex>=0&&this.currentStepIndex<this.steps.length)this.steps[this.currentStepIndex].status="completed",this.steps[this.currentStepIndex].message=e,this.currentStepIndex++}failStep(e){if(this.currentStepIndex>=0&&this.currentStepIndex<this.steps.length)this.steps[this.currentStepIndex].status="failed",this.steps[this.currentStepIndex].error=e}skipStep(e){if(this.currentStepIndex>=0&&this.currentStepIndex<this.steps.length)this.steps[this.currentStepIndex].status="skipped",this.steps[this.currentStepIndex].message=e,this.currentStepIndex++}getStep(e){return this.steps[e]}getSteps(){return this.steps}render(){let e=[];for(let t of this.steps){let a=`${this.getStatusIcon(t.status)} ${t.name}`;if(t.message)a+=` - ${t.message}`;if(t.error)a+=`
|
|
2745
2745
|
Error: ${t.error}`;e.push(a)}return e.join(`
|
|
2746
|
-
`)}getStatusIcon(e){switch(e){case"pending":return"○";case"active":return"◐";case"completed":return"✓";case"failed":return"✗";case"skipped":return"⊘";default:return"○"}}isComplete(){return this.steps.every((e)=>e.status==="completed"||e.status==="skipped")}hasFailed(){return this.steps.some((e)=>e.status==="failed")}}class
|
|
2746
|
+
`)}getStatusIcon(e){switch(e){case"pending":return"○";case"active":return"◐";case"completed":return"✓";case"failed":return"✗";case"skipped":return"⊘";default:return"○"}}isComplete(){return this.steps.every((e)=>e.status==="completed"||e.status==="skipped")}hasFailed(){return this.steps.some((e)=>e.status==="failed")}}class oo{frames=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];currentFrame=0;message;interval=null;constructor(e="Loading..."){this.message=e}start(){if(this.interval)return;this.interval=setInterval(()=>{this.currentFrame=(this.currentFrame+1)%this.frames.length},80)}stop(){if(this.interval)clearInterval(this.interval),this.interval=null}setMessage(e){this.message=e}render(){return`${this.frames[this.currentFrame]} ${this.message}`}succeed(e){return this.stop(),`✓ ${e||this.message}`}fail(e){return this.stop(),`✗ ${e||this.message}`}warn(e){return this.stop(),`⚠ ${e||this.message}`}info(e){return this.stop(),`ℹ ${e||this.message}`}}class co{tasks=[];add(e){return this.tasks.push({title:e,status:"pending"}),this.tasks.length-1}start(e){if(e>=0&&e<this.tasks.length)this.tasks[e].status="running"}complete(e,t){if(e>=0&&e<this.tasks.length)this.tasks[e].status="completed",this.tasks[e].output=t}fail(e,t){if(e>=0&&e<this.tasks.length)this.tasks[e].status="failed",this.tasks[e].output=t}render(){let e=[];for(let t of this.tasks){let a=`${this.getStatusIcon(t.status)} ${t.title}`;if(t.output)a+=`
|
|
2747
2747
|
${t.output}`;e.push(a)}return e.join(`
|
|
2748
|
-
`)}getStatusIcon(e){switch(e){case"pending":return"○";case"running":return"◐";case"completed":return"✓";case"failed":return"✗";default:return"○"}}}function
|
|
2748
|
+
`)}getStatusIcon(e){switch(e){case"pending":return"○";case"running":return"◐";case"completed":return"✓";case"failed":return"✗";default:return"○"}}}function lo(e,t){let a=[];for(let r=0;r<=t.length;r++)a[r]=[r];for(let r=0;r<=e.length;r++)a[0][r]=r;for(let r=1;r<=t.length;r++)for(let n=1;n<=e.length;n++)if(t.charAt(r-1)===e.charAt(n-1))a[r][n]=a[r-1][n-1];else a[r][n]=Math.min(a[r-1][n-1]+1,a[r][n-1]+1,a[r-1][n]+1);return a[t.length][e.length]}function uo(e,t){let a=lo(e.toLowerCase(),t.toLowerCase()),r=Math.max(e.length,t.length);if(r===0)return 1;return 1-a/r}function hr(e,t,a=0.5){return t.map((r)=>({command:r,score:uo(e,r)})).filter((r)=>r.score>=a).sort((r,n)=>n.score-r.score).map((r)=>r.command).slice(0,5)}function td(e,t){if(t.length===0)return`Unknown command: '${e}'
|
|
2749
2749
|
|
|
2750
2750
|
Run 'ts-cloud --help' to see available commands.`;if(t.length===1)return`Unknown command: '${e}'
|
|
2751
2751
|
|
|
@@ -2753,16 +2753,16 @@ Did you mean: ${t[0]}?`;return`Unknown command: '${e}'
|
|
|
2753
2753
|
|
|
2754
2754
|
Did you mean one of these?
|
|
2755
2755
|
${t.map((a)=>` • ${a}`).join(`
|
|
2756
|
-
`)}`}function
|
|
2757
|
-
`)}function
|
|
2758
|
-
`)}function
|
|
2759
|
-
`)}function
|
|
2756
|
+
`)}`}function ad(e,t){return hr(e,t,0.7).length>0}function rd(e,t){let a=t.find((i)=>i.commands.some((s)=>s.name===e||s.aliases?.includes(e)));if(!a)return"No contextual help available.";let r=[];r.push(`${a.name}`),r.push("─".repeat(a.name.length)),r.push(a.description),r.push(""),r.push("Related commands:");for(let i of a.commands)if(r.push(` ${i.name.padEnd(20)} ${i.description}`),i.aliases&&i.aliases.length>0)r.push(` Aliases: ${i.aliases.join(", ")}`);let n=a.commands.find((i)=>i.name===e||i.aliases?.includes(e));if(n?.examples&&n.examples.length>0){r.push(""),r.push("Examples:");for(let i of n.examples)r.push(` ${i}`)}return r.join(`
|
|
2757
|
+
`)}function nd(e,t){let a=[],r=e.toLowerCase();for(let n of t)for(let i of n.commands){let s=i.name.toLowerCase().includes(r),o=i.description.toLowerCase().includes(r),c=i.aliases?.some((l)=>l.toLowerCase().includes(r));if(s||o||c)a.push({command:i,category:n.name})}return a}function id(e,t,a=10){let r=e.toLowerCase(),n=t.filter((s)=>s.toLowerCase().startsWith(r)),i=t.filter((s)=>s.toLowerCase().includes(r)&&!s.toLowerCase().startsWith(r));return[...n,...i].slice(0,a)}function sd(e,t){let a=e.toLowerCase();return t.filter((r)=>{let n=r.name.toLowerCase().includes(a),i=r.alias?.toLowerCase().includes(a);return n||i})}function od(e){if(e.length===0)return"No matching flags found.";let t=[];for(let a of e){let r=` --${a.name}`;if(a.alias)r+=`, -${a.alias}`;if(r=r.padEnd(30),r+=a.description,a.required)r+=" (required)";t.push(r)}return t.join(`
|
|
2758
|
+
`)}function cd(e){let t=[];if(t.push(`Usage: ts-cloud ${e.name}`),t.push(""),t.push(e.description),e.aliases&&e.aliases.length>0)t.push(""),t.push(`Aliases: ${e.aliases.join(", ")}`);if(e.examples&&e.examples.length>0){t.push(""),t.push("Examples:");for(let a of e.examples)t.push(` ${a}`)}return t.join(`
|
|
2759
|
+
`)}function ld(e,t,a=[]){let r={valid:!0,errors:[],warnings:[],suggestions:[]},[n,...i]=e.split(" ");if(!t.includes(n)){r.valid=!1,r.errors.push(`Unknown command: ${n}`);let s=hr(n,t);if(s.length>0)r.suggestions.push(...s)}for(let s of a)if(!i.some((o)=>o===`--${s}`||o.startsWith(`--${s}=`)))r.valid=!1,r.errors.push(`Missing required flag: --${s}`);return r}class mo{options;running=!1;history={commands:[],maxSize:1000};historyIndex=-1;constructor(e){this.options={prompt:e.prompt||"> ",welcome:e.welcome||'Welcome to ts-cloud interactive mode. Type "help" for available commands.',...e}}async start(){if(this.running=!0,this.options.welcome)console.log(this.options.welcome),console.log("");if(this.options.historyFile)await this.loadHistory();while(this.running)try{let e=await this.readInput();if(!e.trim())continue;this.addToHistory(e),await this.executeCommand(e)}catch(e){if(e instanceof Error)console.error(`Error: ${e.message}`)}if(this.options.historyFile)await this.saveHistory()}stop(){this.running=!1}async readInput(){return new Promise((e)=>{process.stdout.write(this.options.prompt||"> "),e("")})}async executeCommand(e){let[t,...a]=this.parseCommand(e);if(t==="exit"||t==="quit"){this.stop();return}if(t==="help"){this.showHelp();return}if(t==="history"){this.showHistory();return}if(t==="clear"){console.clear();return}let r=this.findCommand(t);if(!r){console.error(`Unknown command: ${t}`),console.log('Type "help" to see available commands.');return}try{await r.handler(a)}catch(n){if(n instanceof Error)console.error(`Command failed: ${n.message}`)}}parseCommand(e){return e.trim().split(/\s+/)}findCommand(e){for(let[t,a]of this.options.commands)if(a.name===e||a.aliases?.includes(e))return a;return}showHelp(){console.log("Available commands:"),console.log("");let e=Array.from(this.options.commands.values());console.log(" help Show this help message"),console.log(" history Show command history"),console.log(" clear Clear screen"),console.log(" exit, quit Exit interactive mode"),console.log("");for(let t of e){let a=` ${t.name.padEnd(20)} ${t.description}`;if(t.aliases&&t.aliases.length>0)a+=` (aliases: ${t.aliases.join(", ")})`;console.log(a)}}showHistory(){if(this.history.commands.length===0){console.log("No command history");return}console.log("Command history:"),this.history.commands.forEach((e,t)=>{console.log(` ${(t+1).toString().padStart(4)} ${e}`)})}addToHistory(e){if(this.history.commands[this.history.commands.length-1]===e)return;if(this.history.commands.push(e),this.history.commands.length>this.history.maxSize)this.history.commands=this.history.commands.slice(-this.history.maxSize);this.historyIndex=this.history.commands.length}historyBack(){if(this.historyIndex>0)return this.historyIndex--,this.history.commands[this.historyIndex];return}historyForward(){if(this.historyIndex<this.history.commands.length-1)return this.historyIndex++,this.history.commands[this.historyIndex];return this.historyIndex=this.history.commands.length,""}autocomplete(e){let t=[],a=["help","history","clear","exit","quit"];for(let r of a)if(r.startsWith(e))t.push(r);for(let[r,n]of this.options.commands){if(n.name.startsWith(e))t.push(n.name);if(n.aliases){for(let i of n.aliases)if(i.startsWith(e))t.push(i)}}return t}async loadHistory(){if(!this.options.historyFile)return;try{let e=await(await import("node:fs/promises")).readFile(this.options.historyFile,"utf-8");this.history.commands=e.split(`
|
|
2760
2760
|
`).filter((t)=>t.trim()),this.historyIndex=this.history.commands.length}catch{}}async saveHistory(){if(!this.options.historyFile)return;try{await(await import("node:fs/promises")).writeFile(this.options.historyFile,this.history.commands.join(`
|
|
2761
|
-
`))}catch(e){console.error(`Failed to save history: ${e}`)}}searchHistory(e){return this.history.commands.filter((t)=>t.includes(e))}clearHistory(){this.history.commands=[],this.historyIndex=0}}class
|
|
2762
|
-
`)}importJSON(e){let t=JSON.parse(e).map((a)=>({...a,timestamp:new Date(a.timestamp)}));if(this.entries.push(...t),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}groupByDate(){let e=new Map;for(let t of this.entries){let a=t.timestamp.toISOString().split("T")[0];if(!e.has(a))e.set(a,[]);e.get(a).push(t)}return e}groupByCommand(){let e=new Map;for(let t of this.entries){let a=t.command.split(" ")[0];if(!e.has(a))e.set(a,[]);e.get(a).push(t)}return e}replay(e){return this.getByIndex(e)?.command}getSuggestions(e,t=5){let a=e.toLowerCase(),r=this.entries.filter((n)=>n.command.toLowerCase().startsWith(a)).map((n)=>n.command);return[...new Set(r)].slice(0,t)}analyzePatterns(){let e=new Map,t=new Map;for(let r of this.entries){let n=r.timestamp.getHours(),i=r.timestamp.getDay();e.set(n,(e.get(n)||0)+1),t.set(i,(t.get(i)||0)+1)}let a=this.entries.length>0?this.getSuccessful().length/this.entries.length:0;return{timeOfDay:e,dayOfWeek:t,successRate:a}}}function
|
|
2763
|
-
`)}function
|
|
2764
|
-
`)}class hr{deployments=new Map;async deploy(e,t){let a=this.generateDeploymentId(),r={id:a,regions:t.regions.map((n)=>({region:n.code,stackName:this.getStackName(e,n.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(a,r);try{let n=t.regions.find((s)=>s.isPrimary)||t.regions[0];await this.deployToRegion(e,n,r);let i=t.regions.filter((s)=>s.code!==n.code);if(await Promise.all(i.map((s)=>this.deployToRegion(e,s,r))),t.globalResources)await this.deployGlobalResources(r,t);if(t.replication)await this.setupReplication(r,t);if(t.failover?.enabled)await this.setupFailover(r,t);return r.status="deployed",r.endTime=new Date,r}catch(n){throw r.status="failed",r.endTime=new Date,n}}async deployToRegion(e,t,a){let r=a.regions.find((n)=>n.region===t.code);if(!r)throw Error(`Region deployment not found: ${t.code}`);r.status="deploying",r.startTime=new Date;try{let n=this.createRegionConfig(e,t);await this.deployStack(r.stackName,n,t.code),r.status="deployed",r.endTime=new Date,r.outputs={stackId:`arn:aws:cloudformation:${t.code}:123456789012:stack/${r.stackName}/guid`,endpoint:`https://${r.stackName}.${t.code}.example.com`}}catch(n){throw r.status="failed",r.endTime=new Date,r.error=n instanceof Error?n.message:String(n),n}}async deployGlobalResources(e,t){let a={};if(t.globalResources?.route53)a.route53=await this.deployRoute53(e,t);if(t.globalResources?.cloudfront)a.cloudfront=await this.deployCloudFront(e,t);if(t.globalResources?.waf)a.waf=await this.deployWAF(e);e.globalResources=a}async deployRoute53(e,t){let a=[],r=[];for(let n of e.regions){if(n.status!=="deployed")continue;let i={id:`health-${n.region}`,endpoint:n.outputs?.endpoint,path:t.failover?.healthCheckPath||"/health",region:n.region};a.push(i);let s={name:"example.com",type:"A",region:n.region,setIdentifier:n.region,healthCheckId:i.id,resourceRecords:[n.outputs?.endpoint]};r.push(s)}return{healthChecks:a,recordSets:r,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(e,t){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:e.regions.filter((a)=>a.status==="deployed").map((a,r)=>{let n=t.regions[r];return{id:`origin-${a.region}`,domainName:a.outputs?.endpoint,weight:n?.weight||100}}),status:"Deployed"}}async deployWAF(e){return{webAclId:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6",webAclArn:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6"}}async setupReplication(e,t){if(t.replication?.s3)await this.setupS3Replication(e);if(t.replication?.dynamodb)await this.setupDynamoDBReplication(e);if(t.replication?.secrets)await this.setupSecretsReplication(e)}async setupS3Replication(e){let t=e.regions.filter((a)=>a.status==="deployed");for(let a=0;a<t.length-1;a++){let r=t[a],n=t[a+1];console.log(`Setting up S3 replication: ${r.region} -> ${n.region}`)}}async setupDynamoDBReplication(e){let t=e.regions.filter((a)=>a.status==="deployed").map((a)=>a.region);console.log(`Setting up DynamoDB global table in regions: ${t.join(", ")}`)}async setupSecretsReplication(e){let t=e.regions.filter((a)=>a.status==="deployed").map((a)=>a.region);console.log(`Setting up Secrets Manager replication in regions: ${t.join(", ")}`)}async setupFailover(e,t){let a=e.regions.find((n,i)=>t.regions[i]?.isPrimary)||e.regions[0],r=e.regions.filter((n)=>n.region!==a.region);console.log(`Setting up failover: primary=${a.region}, secondary=${r.map((n)=>n.region).join(", ")}`)}async destroy(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);t.status="rolling-back";try{if(t.globalResources)await this.destroyGlobalResources(t.globalResources);await Promise.all(t.regions.map((a)=>this.destroyRegionStack(a))),this.deployments.delete(e)}catch(a){throw t.status="failed",a}}async destroyGlobalResources(e){if(e.waf)console.log("Destroying WAF resources");if(e.cloudfront)console.log("Destroying CloudFront distribution");if(e.route53)console.log("Destroying Route53 resources")}async destroyRegionStack(e){if(e.status!=="deployed")return;e.status="rolling-back";try{console.log(`Destroying stack ${e.stackName} in ${e.region}`),e.status="pending"}catch(t){throw e.status="failed",e.error=t instanceof Error?t.message:String(t),t}}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getStackName(e,t){return`${e.project.slug}-${t}`}createRegionConfig(e,t){return{...e,infrastructure:{...e.infrastructure}}}async deployStack(e,t,a){console.log(`Deploying stack ${e} to ${a}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var dd=new hr;class yr{references=[];exports=new Map;addExport(e){let t=`${e.region}:${e.exportName}`;if(!this.exports.has(e.region))this.exports.set(e.region,[]);this.exports.get(e.region).push(e)}getExport(e,t){let a=this.exports.get(e);if(!a)return;return a.find((r)=>r.exportName===t)?.value}createReference(e,t,a,r){let n=`/cross-region/${e}/${a}/${r}`;return this.references.push({sourceRegion:e,targetRegion:t,resourceType:a,resourceId:r,value:n}),n}async resolveReference(e,t){let a=this.references.find((r)=>r.targetRegion===e&&r.value===t);if(!a)throw Error(`Reference not found: ${t}`);return`arn:aws:resource:${a.sourceRegion}:123456789012:${a.resourceType}/${a.resourceId}`}getReferencesForRegion(e){return this.references.filter((t)=>t.sourceRegion===e||t.targetRegion===e)}clear(){this.references=[],this.exports.clear()}}class fr{resources=new Map;register(e){this.resources.set(e.id,e)}get(e){return this.resources.get(e)}getByType(e){return Array.from(this.resources.values()).filter((t)=>t.type===e)}getCloudFrontDistributions(){return this.getByType("cloudfront")}getRoute53HostedZones(){return this.getByType("route53")}getWAFWebACLs(){return this.getByType("waf")}remove(e){this.resources.delete(e)}clear(){this.resources.clear()}}class Sr{pairs=[];addPair(e){this.pairs.push(e)}getPairedRegion(e){let t=this.pairs.find((a)=>a.primary===e||a.secondary===e);if(!t)return;return t.primary===e?t.secondary:t.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((e)=>e.replicationConfig)}getFailoverPairs(){return this.pairs.filter((e)=>e.failoverConfig?.automatic)}arePaired(e,t){return this.pairs.some((a)=>a.primary===e&&a.secondary===t||a.primary===t&&a.secondary===e)}clear(){this.pairs=[]}}class br{dependencies=[];addDependency(e){this.dependencies.push(e)}getDependencies(e,t){return this.dependencies.filter((a)=>a.dependentStack===e&&a.dependentRegion===t)}getDependents(e,t){return this.dependencies.filter((a)=>a.dependsOnStack===e&&a.dependsOnRegion===t)}hasDependencies(e,t){return this.getDependencies(e,t).length>0}getDeploymentOrder(e){let t=new Set,a=[],r=(n)=>{let i=`${n.name}:${n.region}`;if(t.has(i))return;t.add(i);let s=this.getDependencies(n.name,n.region);for(let o of s)r({name:o.dependsOnStack,region:o.dependsOnRegion});a.push(n)};for(let n of e)r(n);return a}detectCircularDependencies(){let e=new Set,t=new Set,a=(r,n)=>{let i=`${r}:${n}`;if(t.has(i))return!0;if(e.has(i))return!1;e.add(i),t.add(i);let s=this.getDependencies(r,n);for(let o of s)if(a(o.dependsOnStack,o.dependsOnRegion))return!0;return t.delete(i),!1};for(let r of this.dependencies)if(a(r.dependentStack,r.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var md=new yr,pd=new fr,gd=new Sr,hd=new br,se=[{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 $e(e){return se.find((t)=>t.code===e)}function yd(){return se}function fd(e){let t=e.toLowerCase();return se.filter((a)=>a.location.toLowerCase().includes(t))}function Sd(e){return se.filter((t)=>t.compliance.includes(e))}function bd(e){return se.filter((t)=>t.pricing.tier===e)}function Ad(e){return se.some((t)=>t.code===e)}function Cd(e){if(e.continent==="North America")return $e("us-east-1");if(e.continent==="Europe")return $e("eu-west-1");if(e.continent==="Asia")return $e("ap-southeast-1");return $e("us-east-1")}function Td(e){let t=[...se];if(e.compliance)t=t.filter((a)=>e.compliance.every((r)=>a.compliance.includes(r)));if(e.requiredServices)t=t.filter((a)=>e.requiredServices.every((r)=>a.services[r]));if(e.pricingSensitive)t.sort((a,r)=>a.pricing.multiplier-r.pricing.multiplier);return t.slice(0,5)}function vd(e){let t=$e(e);if(!t)throw Error(`Invalid region: ${e}`);let a=[];for(let r of se){if(r.code===e)continue;let n=ho(t,r),i=yo(t,r);a.push({primary:t,secondary:r,distance:n,sameContinent:i})}return a.sort((r,n)=>{if(r.sameContinent!==n.sameContinent)return r.sameContinent?1:-1;return r.distance-n.distance}),a.slice(0,3)}function ho(e,t){let a={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},r=et(e.location),n=et(t.location);return Math.abs((a[r]||0)-(a[n]||0))}function yo(e,t){return et(e.location)===et(t.location)}function et(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 fo(e){return`${e.name} (${e.code})`}function wd(e){return e.map((t)=>fo(t)).join(`
|
|
2765
|
-
`)}function Ed(){let e={total:se.length,byContinent:{},byPricingTier:{}};for(let t of se){let a=et(t.location);e.byContinent[a]=(e.byContinent[a]||0)+1,e.byPricingTier[t.pricing.tier]=(e.byPricingTier[t.pricing.tier]||0)+1}return e}class Ar{accounts=new Map;crossAccountRoles=[];accountMappings=[];registerAccount(e){this.accounts.set(e.id,e)}getAccount(e){return this.accounts.get(e)}getAccountByAlias(e){return Array.from(this.accounts.values()).find((t)=>t.alias===e)}listAccounts(){return Array.from(this.accounts.values())}getAccountsByRole(e){return Array.from(this.accounts.values()).filter((t)=>t.role===e)}createCrossAccountRole(e,t,a,r,n){let i={roleArn:`arn:aws:iam::${t}:role/${a}`,roleName:a,sourceAccountId:e,targetAccountId:t,permissions:r,externalId:n?.externalId,sessionDuration:n?.sessionDuration||3600};return this.crossAccountRoles.push(i),i}getAssumeRolePolicyDocument(e,t){let a={Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e}:root`},Action:"sts:AssumeRole"}]};if(t)a.Statement[0].Condition={StringEquals:{"sts:ExternalId":t}};return a}generateCrossAccountPolicy(e){return{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e,Resource:"*"}]}}mapEnvironmentToAccount(e,t,a){this.accountMappings.push({environment:e,accountId:t,region:a})}getAccountForEnvironment(e){return this.accountMappings.find((t)=>t.environment===e)}async assumeRole(e,t,a){return console.log(`Assuming role: ${e} with session: ${t}`),{accessKeyId:"AKIAIOSFODNN7EXAMPLE",secretAccessKey:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",sessionToken:"token",expiration:new Date(Date.now()+3600000)}}async getCredentialsForAccount(e){let t=this.accounts.get(e);if(!t)throw Error(`Account not found: ${e}`);if(t.assumeRoleArn){let a=await this.assumeRole(t.assumeRoleArn,`ts-cloud-${Date.now()}`);return{accessKeyId:a.accessKeyId,secretAccessKey:a.secretAccessKey,sessionToken:a.sessionToken}}throw Error("No credentials available for account")}listCrossAccountRoles(){return[...this.crossAccountRoles]}getCrossAccountRolesForAccount(e){return this.crossAccountRoles.filter((t)=>t.sourceAccountId===e||t.targetAccountId===e)}async validateAccountAccess(e){try{let t=await this.getCredentialsForAccount(e);return console.log(`Validating access to account: ${e}`),!0}catch{return!1}}async getConsolidatedBilling(){let e={};for(let t of this.accounts.values())e[t.id]=Math.random()*1000;return{totalCost:Object.values(e).reduce((t,a)=>t+a,0),byAccount:e}}clear(){this.accounts.clear(),this.crossAccountRoles=[],this.accountMappings=[]}}class Cr{organizationId;organizationalUnits=new Map;getOrganizationId(){return this.organizationId}setOrganizationId(e){this.organizationId=e}createOrganizationalUnit(e,t){let a={id:`ou-${Date.now()}`,name:e,parentId:t,accounts:[]};return this.organizationalUnits.set(a.id,a),a}getOrganizationalUnit(e){return this.organizationalUnits.get(e)}listOrganizationalUnits(){return Array.from(this.organizationalUnits.values())}addAccountToOU(e,t){let a=this.organizationalUnits.get(e);if(!a)throw Error(`Organizational unit not found: ${e}`);if(!a.accounts.includes(t))a.accounts.push(t)}removeAccountFromOU(e,t){let a=this.organizationalUnits.get(e);if(!a)throw Error(`Organizational unit not found: ${e}`);a.accounts=a.accounts.filter((r)=>r!==t)}getAccountsInOU(e){let t=this.organizationalUnits.get(e);if(!t)return[];return[...t.accounts]}applyServiceControlPolicy(e,t){return{id:`scp-${Date.now()}`,name:"Custom SCP",targetId:e,policyDocument:t}}clear(){this.organizationId=void 0,this.organizationalUnits.clear()}}var Pd=new Ar,Id=new Cr,So={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"}]}},Rd={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"]}}}]}}},Nd={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 Dd(e){return So[e]}function kd(e,t){return{Type:"AWS::IAM::Role",Properties:{RoleName:e.roleName,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e.sourceAccountId}:root`},Action:"sts:AssumeRole",...e.externalId&&{Condition:{StringEquals:{"sts:ExternalId":e.externalId}}}}]},Policies:[{PolicyName:`${e.roleName}Policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e.permissions,Resource:"*"}]}}],...t&&{ManagedPolicyArns:t},MaxSessionDuration:e.sessionDuration||3600,Tags:[{Key:"ManagedBy",Value:"TS-Cloud"},{Key:"SourceAccount",Value:e.sourceAccountId}]}}}function Md(e){let t=[],a=[],r=e.accounts.filter((c)=>c.role==="management");if(r.length===0)t.push("No management account defined");if(r.length>1)t.push("Multiple management accounts defined");let n=e.accounts.map((c)=>c.email),i=n.filter((c,l)=>n.indexOf(c)!==l);if(i.length>0)t.push(`Duplicate email addresses: ${i.join(", ")}`);let s=e.accounts.map((c)=>c.alias),o=s.filter((c,l)=>s.indexOf(c)!==l);if(o.length>0)t.push(`Duplicate aliases: ${o.join(", ")}`);if(!e.accounts.some((c)=>c.role==="security"))a.push("No dedicated security account - consider adding one for audit logs");if(e.accounts.length<3)a.push("Less than 3 accounts - consider separating environments");if(!e.accounts.some((c)=>c.role==="production"))a.push("No production account defined");return{valid:t.length===0,errors:t,warnings:a}}function Ld(e){let t=[];if(t.push(`${e.name}`),t.push("─".repeat(e.name.length)),t.push(e.description),t.push(""),e.organizationalUnits){t.push("Organizational Units:");for(let a of e.organizationalUnits){let r=a.parent?" └─ ":" ";t.push(`${r}${a.name}`)}t.push("")}t.push("Accounts:");for(let a of e.accounts)t.push(` ${a.alias.padEnd(20)} ${a.role.padEnd(15)} ${a.email}`),t.push(` ${"".padEnd(20)} ${a.description}`),t.push("");return t.join(`
|
|
2761
|
+
`))}catch(e){console.error(`Failed to save history: ${e}`)}}searchHistory(e){return this.history.commands.filter((t)=>t.includes(e))}clearHistory(){this.history.commands=[],this.historyIndex=0}}class po{variables=new Map;workingDirectory=process.cwd();set(e,t){this.variables.set(e,t)}get(e){return this.variables.get(e)}has(e){return this.variables.has(e)}delete(e){this.variables.delete(e)}getAll(){return Object.fromEntries(this.variables)}clear(){this.variables.clear()}setWorkingDirectory(e){this.workingDirectory=e}getWorkingDirectory(){return this.workingDirectory}}class go{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 ho{entries=[];maxSize;persistFile;trackOutput;constructor(e={}){this.maxSize=e.maxSize||1000,this.persistFile=e.persistFile,this.trackOutput=e.trackOutput||!1}add(e){if(this.entries.push({...e,timestamp:new Date}),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}getAll(){return[...this.entries]}getRecent(e=10){return this.entries.slice(-e)}search(e){let t=e.toLowerCase();return this.entries.filter((a)=>a.command.toLowerCase().includes(t))}searchByDate(e,t){return this.entries.filter((a)=>a.timestamp>=e&&a.timestamp<=t)}getSuccessful(){return this.entries.filter((e)=>e.success)}getFailed(){return this.entries.filter((e)=>!e.success)}getMostUsed(e=10){let t=new Map;for(let a of this.entries){let r=a.command.split(" ")[0];t.set(r,(t.get(r)||0)+1)}return Array.from(t.entries()).map(([a,r])=>({command:a,count:r})).sort((a,r)=>r.count-a.count).slice(0,e)}getStats(){let e=this.entries.length,t=this.entries.filter((o)=>o.success).length,a=this.entries.filter((o)=>!o.success).length,r=this.entries.filter((o)=>o.duration!==void 0),n=r.length>0?r.reduce((o,c)=>o+(c.duration||0),0)/r.length:0,i=this.getMostUsed(1),s=i.length>0?i[0].command:"N/A";return{total:e,successful:t,failed:a,averageDuration:n,mostUsed:s}}clear(){this.entries=[]}getByIndex(e){if(e<0||e>=this.entries.length)return;return this.entries[e]}removeByIndex(e){if(e>=0&&e<this.entries.length)this.entries.splice(e,1)}async save(){if(!this.persistFile)return;try{let e=await import("node:fs/promises"),t=JSON.stringify(this.entries,null,2);await e.writeFile(this.persistFile,t,"utf-8")}catch(e){throw Error(`Failed to save history: ${e}`)}}async load(){if(!this.persistFile)return;try{let e=await(await import("node:fs/promises")).readFile(this.persistFile,"utf-8"),t=JSON.parse(e);this.entries=t.map((a)=>({...a,timestamp:new Date(a.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(`
|
|
2762
|
+
`)}importJSON(e){let t=JSON.parse(e).map((a)=>({...a,timestamp:new Date(a.timestamp)}));if(this.entries.push(...t),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}groupByDate(){let e=new Map;for(let t of this.entries){let a=t.timestamp.toISOString().split("T")[0];if(!e.has(a))e.set(a,[]);e.get(a).push(t)}return e}groupByCommand(){let e=new Map;for(let t of this.entries){let a=t.command.split(" ")[0];if(!e.has(a))e.set(a,[]);e.get(a).push(t)}return e}replay(e){return this.getByIndex(e)?.command}getSuggestions(e,t=5){let a=e.toLowerCase(),r=this.entries.filter((n)=>n.command.toLowerCase().startsWith(a)).map((n)=>n.command);return[...new Set(r)].slice(0,t)}analyzePatterns(){let e=new Map,t=new Map;for(let r of this.entries){let n=r.timestamp.getHours(),i=r.timestamp.getDay();e.set(n,(e.get(n)||0)+1),t.set(i,(t.get(i)||0)+1)}let a=this.entries.length>0?this.getSuccessful().length/this.entries.length:0;return{timeOfDay:e,dayOfWeek:t,successRate:a}}}function ud(e,t={}){let{maxWidth:a=100}=t;if(e.length===0)return"No command history";let r=[];for(let n=0;n<e.length;n++){let i=e[n],s=(n+1).toString().padStart(4),o=i.timestamp.toLocaleString(),c=i.success?"✓":"✗",l=i.command;if(l.length>a-30)l=l.substring(0,a-33)+"...";let u=`${s} ${o} ${c} ${l}`;if(i.duration)u+=` (${i.duration}ms)`;r.push(u)}return r.join(`
|
|
2763
|
+
`)}function dd(e){let t=[];return t.push("Command History Statistics"),t.push("─".repeat(30)),t.push(`Total commands: ${e.total}`),t.push(`Successful: ${e.successful}`),t.push(`Failed: ${e.failed}`),t.push(`Success rate: ${(e.successful/e.total*100).toFixed(1)}%`),t.push(`Average duration: ${e.averageDuration.toFixed(0)}ms`),t.push(`Most used: ${e.mostUsed}`),t.join(`
|
|
2764
|
+
`)}class yr{deployments=new Map;async deploy(e,t){let a=this.generateDeploymentId(),r={id:a,regions:t.regions.map((n)=>({region:n.code,stackName:this.getStackName(e,n.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(a,r);try{let n=t.regions.find((s)=>s.isPrimary)||t.regions[0];await this.deployToRegion(e,n,r);let i=t.regions.filter((s)=>s.code!==n.code);if(await Promise.all(i.map((s)=>this.deployToRegion(e,s,r))),t.globalResources)await this.deployGlobalResources(r,t);if(t.replication)await this.setupReplication(r,t);if(t.failover?.enabled)await this.setupFailover(r,t);return r.status="deployed",r.endTime=new Date,r}catch(n){throw r.status="failed",r.endTime=new Date,n}}async deployToRegion(e,t,a){let r=a.regions.find((n)=>n.region===t.code);if(!r)throw Error(`Region deployment not found: ${t.code}`);r.status="deploying",r.startTime=new Date;try{let n=this.createRegionConfig(e,t);await this.deployStack(r.stackName,n,t.code),r.status="deployed",r.endTime=new Date,r.outputs={stackId:`arn:aws:cloudformation:${t.code}:123456789012:stack/${r.stackName}/guid`,endpoint:`https://${r.stackName}.${t.code}.example.com`}}catch(n){throw r.status="failed",r.endTime=new Date,r.error=n instanceof Error?n.message:String(n),n}}async deployGlobalResources(e,t){let a={};if(t.globalResources?.route53)a.route53=await this.deployRoute53(e,t);if(t.globalResources?.cloudfront)a.cloudfront=await this.deployCloudFront(e,t);if(t.globalResources?.waf)a.waf=await this.deployWAF(e);e.globalResources=a}async deployRoute53(e,t){let a=[],r=[];for(let n of e.regions){if(n.status!=="deployed")continue;let i={id:`health-${n.region}`,endpoint:n.outputs?.endpoint,path:t.failover?.healthCheckPath||"/health",region:n.region};a.push(i);let s={name:"example.com",type:"A",region:n.region,setIdentifier:n.region,healthCheckId:i.id,resourceRecords:[n.outputs?.endpoint]};r.push(s)}return{healthChecks:a,recordSets:r,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(e,t){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:e.regions.filter((a)=>a.status==="deployed").map((a,r)=>{let n=t.regions[r];return{id:`origin-${a.region}`,domainName:a.outputs?.endpoint,weight:n?.weight||100}}),status:"Deployed"}}async deployWAF(e){return{webAclId:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6",webAclArn:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6"}}async setupReplication(e,t){if(t.replication?.s3)await this.setupS3Replication(e);if(t.replication?.dynamodb)await this.setupDynamoDBReplication(e);if(t.replication?.secrets)await this.setupSecretsReplication(e)}async setupS3Replication(e){let t=e.regions.filter((a)=>a.status==="deployed");for(let a=0;a<t.length-1;a++){let r=t[a],n=t[a+1];console.log(`Setting up S3 replication: ${r.region} -> ${n.region}`)}}async setupDynamoDBReplication(e){let t=e.regions.filter((a)=>a.status==="deployed").map((a)=>a.region);console.log(`Setting up DynamoDB global table in regions: ${t.join(", ")}`)}async setupSecretsReplication(e){let t=e.regions.filter((a)=>a.status==="deployed").map((a)=>a.region);console.log(`Setting up Secrets Manager replication in regions: ${t.join(", ")}`)}async setupFailover(e,t){let a=e.regions.find((n,i)=>t.regions[i]?.isPrimary)||e.regions[0],r=e.regions.filter((n)=>n.region!==a.region);console.log(`Setting up failover: primary=${a.region}, secondary=${r.map((n)=>n.region).join(", ")}`)}async destroy(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);t.status="rolling-back";try{if(t.globalResources)await this.destroyGlobalResources(t.globalResources);await Promise.all(t.regions.map((a)=>this.destroyRegionStack(a))),this.deployments.delete(e)}catch(a){throw t.status="failed",a}}async destroyGlobalResources(e){if(e.waf)console.log("Destroying WAF resources");if(e.cloudfront)console.log("Destroying CloudFront distribution");if(e.route53)console.log("Destroying Route53 resources")}async destroyRegionStack(e){if(e.status!=="deployed")return;e.status="rolling-back";try{console.log(`Destroying stack ${e.stackName} in ${e.region}`),e.status="pending"}catch(t){throw e.status="failed",e.error=t instanceof Error?t.message:String(t),t}}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getStackName(e,t){return`${e.project.slug}-${t}`}createRegionConfig(e,t){return{...e,infrastructure:{...e.infrastructure}}}async deployStack(e,t,a){console.log(`Deploying stack ${e} to ${a}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var md=new yr;class fr{references=[];exports=new Map;addExport(e){let t=`${e.region}:${e.exportName}`;if(!this.exports.has(e.region))this.exports.set(e.region,[]);this.exports.get(e.region).push(e)}getExport(e,t){let a=this.exports.get(e);if(!a)return;return a.find((r)=>r.exportName===t)?.value}createReference(e,t,a,r){let n=`/cross-region/${e}/${a}/${r}`;return this.references.push({sourceRegion:e,targetRegion:t,resourceType:a,resourceId:r,value:n}),n}async resolveReference(e,t){let a=this.references.find((r)=>r.targetRegion===e&&r.value===t);if(!a)throw Error(`Reference not found: ${t}`);return`arn:aws:resource:${a.sourceRegion}:123456789012:${a.resourceType}/${a.resourceId}`}getReferencesForRegion(e){return this.references.filter((t)=>t.sourceRegion===e||t.targetRegion===e)}clear(){this.references=[],this.exports.clear()}}class Sr{resources=new Map;register(e){this.resources.set(e.id,e)}get(e){return this.resources.get(e)}getByType(e){return Array.from(this.resources.values()).filter((t)=>t.type===e)}getCloudFrontDistributions(){return this.getByType("cloudfront")}getRoute53HostedZones(){return this.getByType("route53")}getWAFWebACLs(){return this.getByType("waf")}remove(e){this.resources.delete(e)}clear(){this.resources.clear()}}class br{pairs=[];addPair(e){this.pairs.push(e)}getPairedRegion(e){let t=this.pairs.find((a)=>a.primary===e||a.secondary===e);if(!t)return;return t.primary===e?t.secondary:t.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((e)=>e.replicationConfig)}getFailoverPairs(){return this.pairs.filter((e)=>e.failoverConfig?.automatic)}arePaired(e,t){return this.pairs.some((a)=>a.primary===e&&a.secondary===t||a.primary===t&&a.secondary===e)}clear(){this.pairs=[]}}class Ar{dependencies=[];addDependency(e){this.dependencies.push(e)}getDependencies(e,t){return this.dependencies.filter((a)=>a.dependentStack===e&&a.dependentRegion===t)}getDependents(e,t){return this.dependencies.filter((a)=>a.dependsOnStack===e&&a.dependsOnRegion===t)}hasDependencies(e,t){return this.getDependencies(e,t).length>0}getDeploymentOrder(e){let t=new Set,a=[],r=(n)=>{let i=`${n.name}:${n.region}`;if(t.has(i))return;t.add(i);let s=this.getDependencies(n.name,n.region);for(let o of s)r({name:o.dependsOnStack,region:o.dependsOnRegion});a.push(n)};for(let n of e)r(n);return a}detectCircularDependencies(){let e=new Set,t=new Set,a=(r,n)=>{let i=`${r}:${n}`;if(t.has(i))return!0;if(e.has(i))return!1;e.add(i),t.add(i);let s=this.getDependencies(r,n);for(let o of s)if(a(o.dependsOnStack,o.dependsOnRegion))return!0;return t.delete(i),!1};for(let r of this.dependencies)if(a(r.dependentStack,r.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var pd=new fr,gd=new Sr,hd=new br,yd=new Ar,oe=[{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 Ye(e){return oe.find((t)=>t.code===e)}function fd(){return oe}function Sd(e){let t=e.toLowerCase();return oe.filter((a)=>a.location.toLowerCase().includes(t))}function bd(e){return oe.filter((t)=>t.compliance.includes(e))}function Ad(e){return oe.filter((t)=>t.pricing.tier===e)}function Cd(e){return oe.some((t)=>t.code===e)}function Td(e){if(e.continent==="North America")return Ye("us-east-1");if(e.continent==="Europe")return Ye("eu-west-1");if(e.continent==="Asia")return Ye("ap-southeast-1");return Ye("us-east-1")}function vd(e){let t=[...oe];if(e.compliance)t=t.filter((a)=>e.compliance.every((r)=>a.compliance.includes(r)));if(e.requiredServices)t=t.filter((a)=>e.requiredServices.every((r)=>a.services[r]));if(e.pricingSensitive)t.sort((a,r)=>a.pricing.multiplier-r.pricing.multiplier);return t.slice(0,5)}function wd(e){let t=Ye(e);if(!t)throw Error(`Invalid region: ${e}`);let a=[];for(let r of oe){if(r.code===e)continue;let n=yo(t,r),i=fo(t,r);a.push({primary:t,secondary:r,distance:n,sameContinent:i})}return a.sort((r,n)=>{if(r.sameContinent!==n.sameContinent)return r.sameContinent?1:-1;return r.distance-n.distance}),a.slice(0,3)}function yo(e,t){let a={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},r=tt(e.location),n=tt(t.location);return Math.abs((a[r]||0)-(a[n]||0))}function fo(e,t){return tt(e.location)===tt(t.location)}function tt(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 So(e){return`${e.name} (${e.code})`}function Ed(e){return e.map((t)=>So(t)).join(`
|
|
2765
|
+
`)}function Pd(){let e={total:oe.length,byContinent:{},byPricingTier:{}};for(let t of oe){let a=tt(t.location);e.byContinent[a]=(e.byContinent[a]||0)+1,e.byPricingTier[t.pricing.tier]=(e.byPricingTier[t.pricing.tier]||0)+1}return e}class Cr{accounts=new Map;crossAccountRoles=[];accountMappings=[];registerAccount(e){this.accounts.set(e.id,e)}getAccount(e){return this.accounts.get(e)}getAccountByAlias(e){return Array.from(this.accounts.values()).find((t)=>t.alias===e)}listAccounts(){return Array.from(this.accounts.values())}getAccountsByRole(e){return Array.from(this.accounts.values()).filter((t)=>t.role===e)}createCrossAccountRole(e,t,a,r,n){let i={roleArn:`arn:aws:iam::${t}:role/${a}`,roleName:a,sourceAccountId:e,targetAccountId:t,permissions:r,externalId:n?.externalId,sessionDuration:n?.sessionDuration||3600};return this.crossAccountRoles.push(i),i}getAssumeRolePolicyDocument(e,t){let a={Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e}:root`},Action:"sts:AssumeRole"}]};if(t)a.Statement[0].Condition={StringEquals:{"sts:ExternalId":t}};return a}generateCrossAccountPolicy(e){return{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e,Resource:"*"}]}}mapEnvironmentToAccount(e,t,a){this.accountMappings.push({environment:e,accountId:t,region:a})}getAccountForEnvironment(e){return this.accountMappings.find((t)=>t.environment===e)}async assumeRole(e,t,a){return console.log(`Assuming role: ${e} with session: ${t}`),{accessKeyId:"AKIAIOSFODNN7EXAMPLE",secretAccessKey:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",sessionToken:"token",expiration:new Date(Date.now()+3600000)}}async getCredentialsForAccount(e){let t=this.accounts.get(e);if(!t)throw Error(`Account not found: ${e}`);if(t.assumeRoleArn){let a=await this.assumeRole(t.assumeRoleArn,`ts-cloud-${Date.now()}`);return{accessKeyId:a.accessKeyId,secretAccessKey:a.secretAccessKey,sessionToken:a.sessionToken}}throw Error("No credentials available for account")}listCrossAccountRoles(){return[...this.crossAccountRoles]}getCrossAccountRolesForAccount(e){return this.crossAccountRoles.filter((t)=>t.sourceAccountId===e||t.targetAccountId===e)}async validateAccountAccess(e){try{let t=await this.getCredentialsForAccount(e);return console.log(`Validating access to account: ${e}`),!0}catch{return!1}}async getConsolidatedBilling(){let e={};for(let t of this.accounts.values())e[t.id]=Math.random()*1000;return{totalCost:Object.values(e).reduce((t,a)=>t+a,0),byAccount:e}}clear(){this.accounts.clear(),this.crossAccountRoles=[],this.accountMappings=[]}}class Tr{organizationId;organizationalUnits=new Map;getOrganizationId(){return this.organizationId}setOrganizationId(e){this.organizationId=e}createOrganizationalUnit(e,t){let a={id:`ou-${Date.now()}`,name:e,parentId:t,accounts:[]};return this.organizationalUnits.set(a.id,a),a}getOrganizationalUnit(e){return this.organizationalUnits.get(e)}listOrganizationalUnits(){return Array.from(this.organizationalUnits.values())}addAccountToOU(e,t){let a=this.organizationalUnits.get(e);if(!a)throw Error(`Organizational unit not found: ${e}`);if(!a.accounts.includes(t))a.accounts.push(t)}removeAccountFromOU(e,t){let a=this.organizationalUnits.get(e);if(!a)throw Error(`Organizational unit not found: ${e}`);a.accounts=a.accounts.filter((r)=>r!==t)}getAccountsInOU(e){let t=this.organizationalUnits.get(e);if(!t)return[];return[...t.accounts]}applyServiceControlPolicy(e,t){return{id:`scp-${Date.now()}`,name:"Custom SCP",targetId:e,policyDocument:t}}clear(){this.organizationId=void 0,this.organizationalUnits.clear()}}var Id=new Cr,Rd=new Tr,bo={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"}]}},Nd={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"]}}}]}}},Dd={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 kd(e){return bo[e]}function $d(e,t){return{Type:"AWS::IAM::Role",Properties:{RoleName:e.roleName,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e.sourceAccountId}:root`},Action:"sts:AssumeRole",...e.externalId&&{Condition:{StringEquals:{"sts:ExternalId":e.externalId}}}}]},Policies:[{PolicyName:`${e.roleName}Policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e.permissions,Resource:"*"}]}}],...t&&{ManagedPolicyArns:t},MaxSessionDuration:e.sessionDuration||3600,Tags:[{Key:"ManagedBy",Value:"TS-Cloud"},{Key:"SourceAccount",Value:e.sourceAccountId}]}}}function Ld(e){let t=[],a=[],r=e.accounts.filter((c)=>c.role==="management");if(r.length===0)t.push("No management account defined");if(r.length>1)t.push("Multiple management accounts defined");let n=e.accounts.map((c)=>c.email),i=n.filter((c,l)=>n.indexOf(c)!==l);if(i.length>0)t.push(`Duplicate email addresses: ${i.join(", ")}`);let s=e.accounts.map((c)=>c.alias),o=s.filter((c,l)=>s.indexOf(c)!==l);if(o.length>0)t.push(`Duplicate aliases: ${o.join(", ")}`);if(!e.accounts.some((c)=>c.role==="security"))a.push("No dedicated security account - consider adding one for audit logs");if(e.accounts.length<3)a.push("Less than 3 accounts - consider separating environments");if(!e.accounts.some((c)=>c.role==="production"))a.push("No production account defined");return{valid:t.length===0,errors:t,warnings:a}}function Md(e){let t=[];if(t.push(`${e.name}`),t.push("─".repeat(e.name.length)),t.push(e.description),t.push(""),e.organizationalUnits){t.push("Organizational Units:");for(let a of e.organizationalUnits){let r=a.parent?" └─ ":" ";t.push(`${r}${a.name}`)}t.push("")}t.push("Accounts:");for(let a of e.accounts)t.push(` ${a.alias.padEnd(20)} ${a.role.padEnd(15)} ${a.email}`),t.push(` ${"".padEnd(20)} ${a.description}`),t.push("");return t.join(`
|
|
2766
2766
|
`)}function xd(e={}){let{workflowName:t="Deploy",trigger:a="push",branches:r=["main"],environments:n=["production"],awsRegion:i="us-east-1",awsRole:s,bunVersion:o="latest",deployCommand:c="bun run cloud deploy",testCommand:l="bun test",buildCommand:u="bun run build"}=e,m=!!s;return`name: ${t}
|
|
2767
2767
|
|
|
2768
2768
|
on:
|
|
@@ -2888,7 +2888,7 @@ ${t.map((i,s)=>` ${s>0?"elif":"if"} [[ "\${{ github.ref }}" == "refs/he
|
|
|
2888
2888
|
|
|
2889
2889
|
- name: Deploy
|
|
2890
2890
|
run: bun run cloud deploy --env=\${{ needs.determine-environment.outputs.environment }}
|
|
2891
|
-
`}function
|
|
2891
|
+
`}function Bd(e={}){let{awsRegion:t="us-east-1",awsRole:a,ttl:r=24}=e,n=!!a;return`name: PR Preview Environment
|
|
2892
2892
|
|
|
2893
2893
|
on:
|
|
2894
2894
|
pull_request:
|
|
@@ -3035,7 +3035,7 @@ jobs:
|
|
|
3035
3035
|
|
|
3036
3036
|
- name: Deploy
|
|
3037
3037
|
run: bun run cloud deploy --env=\${{ env.ENVIRONMENT }}
|
|
3038
|
-
`}function
|
|
3038
|
+
`}function Wd(e){let{matrix:t,awsRole:a}=e,r=!!a;return`name: Matrix Deployment
|
|
3039
3039
|
|
|
3040
3040
|
on:
|
|
3041
3041
|
workflow_dispatch:
|
|
@@ -3082,7 +3082,7 @@ ${t.map((n)=>` - environment: ${n.environment}
|
|
|
3082
3082
|
|
|
3083
3083
|
- name: Deploy to \${{ matrix.environment }} (\${{ matrix.region }})
|
|
3084
3084
|
run: bun run cloud deploy --env=\${{ matrix.environment }} --region=\${{ matrix.region }}
|
|
3085
|
-
`}function
|
|
3085
|
+
`}function Gd(e={}){let{stages:t=["test","build","deploy"],environments:a=["production"],awsRegion:r="us-east-1",dockerImage:n="oven/bun:latest",deployCommand:i="bun run cloud deploy",testCommand:s="bun test",buildCommand:o="bun run build"}=e;return`stages:
|
|
3086
3086
|
${t.map((c)=>` - ${c}`).join(`
|
|
3087
3087
|
`)}
|
|
3088
3088
|
|
|
@@ -3130,7 +3130,7 @@ deploy:
|
|
|
3130
3130
|
only:
|
|
3131
3131
|
- main
|
|
3132
3132
|
when: manual
|
|
3133
|
-
`}function
|
|
3133
|
+
`}function Fd(e){let{environments:t,awsRegion:a="us-east-1"}=e,r=t.map((n)=>`
|
|
3134
3134
|
deploy:${n.name}:
|
|
3135
3135
|
stage: deploy
|
|
3136
3136
|
script:
|
|
@@ -3216,7 +3216,7 @@ cleanup:preview:
|
|
|
3216
3216
|
when: manual
|
|
3217
3217
|
only:
|
|
3218
3218
|
- merge_requests
|
|
3219
|
-
`}function
|
|
3219
|
+
`}function Ud(e){let{environment:t,awsRegion:a="us-east-1"}=e;return`stages:
|
|
3220
3220
|
- deploy
|
|
3221
3221
|
|
|
3222
3222
|
variables:
|
|
@@ -3528,7 +3528,7 @@ workflows:
|
|
|
3528
3528
|
requires:
|
|
3529
3529
|
- test
|
|
3530
3530
|
${n}
|
|
3531
|
-
`}function
|
|
3531
|
+
`}function Qd(e){let{regions:t,environment:a}=e,r=t.map((i)=>`
|
|
3532
3532
|
deploy-${i.replace(/-/g,"_")}:
|
|
3533
3533
|
executor: bun-executor
|
|
3534
3534
|
environment:
|
|
@@ -3597,7 +3597,7 @@ workflows:
|
|
|
3597
3597
|
requires:
|
|
3598
3598
|
- test
|
|
3599
3599
|
${n}
|
|
3600
|
-
`}class Tr{backupPlans=new Map;backupVaults=new Map;restoreJobs=new Map;continuousBackups=new Map;planCounter=0;restoreCounter=0;continuousBackupCounter=0;createVault(e){this.backupVaults.set(e.name,e)}getVault(e){return this.backupVaults.get(e)}createBackupPlan(e){let t=`backup-plan-${Date.now()}-${this.planCounter++}`,a={id:t,...e};return this.backupPlans.set(t,a),a}getBackupPlan(e){return this.backupPlans.get(e)}listBackupPlans(){return Array.from(this.backupPlans.values())}createRDSBackupPlan(e){let{dbInstanceArn:t,schedule:a="0 2 * * *",retentionDays:r=7,vaultName:n="default-vault"}=e;return this.createBackupPlan({name:"RDS Daily Backup",schedule:a,retentionDays:r,vaultName:n,resources:[{resourceArn:t,resourceType:"rds",region:"us-east-1"}],lifecycle:{moveTocoldStorageAfterDays:30,deleteAfterDays:r}})}createDynamoDBBackupPlan(e){let{tableArn:t,schedule:a="0 3 * * *",retentionDays:r=35,crossRegionCopy:n}=e;return this.createBackupPlan({name:"DynamoDB Daily Backup",schedule:a,retentionDays:r,vaultName:"dynamodb-vault",resources:[{resourceArn:t,resourceType:"dynamodb",region:"us-east-1"}],lifecycle:{deleteAfterDays:r},tags:n?{CrossRegionCopy:n.join(",")}:void 0})}createEFSBackupPlan(e){let{fileSystemArn:t,schedule:a="0 1 * * *",retentionDays:r=30}=e;return this.createBackupPlan({name:"EFS Daily Backup",schedule:a,retentionDays:r,vaultName:"efs-vault",resources:[{resourceArn:t,resourceType:"efs",region:"us-east-1"}],lifecycle:{deleteAfterDays:r}})}enableContinuousBackup(e,t=35){let a=`continuous-backup-${Date.now()}-${this.continuousBackupCounter++}`,r={id:a,resourceId:e,enabled:!0,retentionDays:t};return this.continuousBackups.set(a,r),r}getContinuousBackup(e){return this.continuousBackups.get(e)}enablePointInTimeRecovery(e,t){return{enabled:!0,earliestRestorableTime:new Date(Date.now()-604800000),latestRestorableTime:new Date}}async restoreFromBackup(e){let{backupId:t,resourceType:a,targetRegion:r}=e,n={id:`restore-${Date.now()}-${this.restoreCounter++}`,backupId:t,resourceType:a,status:"pending",startTime:new Date,targetRegion:r};return this.restoreJobs.set(n.id,n),setTimeout(()=>{n.status="running"},100),setTimeout(()=>{n.status="completed",n.endTime=new Date},1000),n}async restoreToPointInTime(e){let{sourceResourceArn:t,targetResourceName:a,restoreTime:r,resourceType:n}=e,i={id:`pitr-${Date.now()}-${this.restoreCounter++}`,backupId:`pitr-${r.getTime()}`,resourceType:n,status:"pending",startTime:new Date};return this.restoreJobs.set(i.id,i),console.log(`Restoring ${n} from ${t} to ${a} at ${r.toISOString()}`),setTimeout(()=>{i.status="completed",i.endTime=new Date},2000),i}getRestoreJob(e){return this.restoreJobs.get(e)}listRestoreJobs(){return Array.from(this.restoreJobs.values())}setupCrossRegionReplication(e){let{sourceVault:t,sourceRegion:a,targetRegions:r}=e;console.log("Setting up cross-region replication:"),console.log(` Source: ${t} in ${a}`),console.log(` Targets: ${r.join(", ")}`)}generateBackupVaultCF(e){return{Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:e.name,...e.encryptionKeyArn&&{EncryptionKeyArn:e.encryptionKeyArn},...e.accessPolicy&&{AccessPolicy:e.accessPolicy}}}}generateBackupPlanCF(e){return{Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:e.name,BackupPlanRule:[{RuleName:"DailyBackup",TargetBackupVault:e.vaultName,ScheduleExpression:`cron(${e.schedule})`,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:e.lifecycle?{...e.lifecycle.moveTocoldStorageAfterDays&&{MoveToColdStorageAfterDays:e.lifecycle.moveTocoldStorageAfterDays},...e.lifecycle.deleteAfterDays&&{DeleteAfterDays:e.lifecycle.deleteAfterDays}}:void 0}]},...e.tags&&{BackupPlanTags:e.tags}}}}generateBackupSelectionCF(e){return{Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:{Ref:`BackupPlan${e.id}`},BackupSelection:{SelectionName:`${e.name}Selection`,IamRoleArn:"arn:aws:iam::123456789012:role/service-role/AWSBackupDefaultServiceRole",Resources:e.resources.map((t)=>t.resourceArn)}}}}clear(){this.backupPlans.clear(),this.backupVaults.clear(),this.restoreJobs.clear(),this.continuousBackups.clear(),this.planCounter=0,this.restoreCounter=0,this.continuousBackupCounter=0}}var Qd=new Tr;class vr{drPlans=new Map;failoverTests=new Map;planCounter=0;testCounter=0;createDRPlan(e){let t=`dr-plan-${Date.now()}-${this.planCounter++}`,a={id:t,...e};return this.drPlans.set(t,a),a}createRDSDRPlan(e){let{primaryDbArn:t,secondaryDbArn:a,primaryRegion:r,secondaryRegion:n,rto:i=60,rpo:s=5}=e;return this.createDRPlan({name:"RDS Multi-Region DR",primaryRegion:r,secondaryRegion:n,rto:i,rpo:s,resources:[{resourceId:"primary-db",resourceType:"rds",primaryArn:t,secondaryArn:a,replicationEnabled:!0}],runbook:this.generateRDSRunbook(r,n),testSchedule:"0 0 1 * *"})}createDynamoDBDRPlan(e){let{tableArn:t,regions:a,rto:r=15,rpo:n=1}=e;return this.createDRPlan({name:"DynamoDB Global Tables DR",primaryRegion:a[0],secondaryRegion:a[1],rto:r,rpo:n,resources:[{resourceId:"dynamodb-table",resourceType:"dynamodb",primaryArn:t,replicationEnabled:!0}],runbook:this.generateDynamoDBRunbook(a)})}generateRDSRunbook(e,t){return{estimatedDuration:60,requiredApprovals:["cto","engineering-lead"],steps:[{order:1,name:"Verify Primary Database Failure",description:"Confirm that the primary database is truly unavailable and not experiencing temporary issues",action:"aws rds describe-db-instances --region "+e,automatable:!0,estimatedDuration:2,rollbackable:!1},{order:2,name:"Check Replication Lag",description:"Verify that the read replica is up to date",action:"Check ReplicaLag metric in CloudWatch",automatable:!0,estimatedDuration:1,rollbackable:!1},{order:3,name:"Promote Read Replica",description:"Promote the read replica in the secondary region to be the new primary",action:"aws rds promote-read-replica --db-instance-identifier replica --region "+t,automatable:!0,estimatedDuration:10,rollbackable:!1},{order:4,name:"Update DNS Records",description:"Update Route53 records to point to the new primary database",action:"Update Route53 failover record set",automatable:!0,estimatedDuration:5,rollbackable:!0},{order:5,name:"Update Application Configuration",description:"Update application connection strings if needed",action:"Deploy configuration update to ECS/Lambda",automatable:!0,estimatedDuration:10,rollbackable:!0},{order:6,name:"Verify Application Connectivity",description:"Test that applications can connect to the new primary",action:"Run smoke tests",automatable:!0,estimatedDuration:5,rollbackable:!1},{order:7,name:"Monitor for Issues",description:"Monitor CloudWatch metrics and application logs",action:"Monitor for 30 minutes",automatable:!1,estimatedDuration:30,rollbackable:!1}]}}generateDynamoDBRunbook(e){return{estimatedDuration:15,steps:[{order:1,name:"Verify Primary Region Failure",description:"Confirm that the primary region is experiencing an outage",action:"Check AWS Health Dashboard",automatable:!0,estimatedDuration:2,rollbackable:!1},{order:2,name:"Update Route53 Failover",description:"Update Route53 to direct traffic to secondary region",action:"Update Route53 health check and failover records",automatable:!0,estimatedDuration:5,rollbackable:!0},{order:3,name:"Update Application Endpoints",description:"Update Lambda/ECS to use secondary region DynamoDB endpoint",action:"Deploy configuration update",automatable:!0,estimatedDuration:5,rollbackable:!0},{order:4,name:"Verify Data Consistency",description:"Verify that data is consistent in secondary region",action:"Run data validation queries",automatable:!0,estimatedDuration:3,rollbackable:!1}]}}async executeFailover(e,t=!1){let a=this.drPlans.get(e);if(!a)throw Error(`DR plan not found: ${e}`);let r=Date.now(),n=0;console.log(`${t?"[DRY RUN] ":""}Executing failover for plan: ${a.name}`),console.log(`Primary: ${a.primaryRegion} -> Secondary: ${a.secondaryRegion}`),console.log(`RTO: ${a.rto} minutes, RPO: ${a.rpo} minutes`),console.log("");for(let i of a.runbook.steps){if(console.log(`Step ${i.order}: ${i.name}`),console.log(` ${i.description}`),console.log(` Action: ${i.action}`),console.log(` Estimated: ${i.estimatedDuration} minutes`),t)console.log(" [SKIPPED - DRY RUN]");else if(i.automatable)console.log(" [AUTOMATED]");else console.log(" [MANUAL - WAITING]");n++,console.log("")}return{success:!0,duration:(Date.now()-r)/1000/60,completedSteps:n}}scheduleFailoverTest(e,t){let a={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:e,status:"scheduled",startTime:t};return this.failoverTests.set(a.id,a),a}async runFailoverTest(e){let t=this.drPlans.get(e);if(!t)throw Error(`DR plan not found: ${e}`);let a={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:e,status:"running",startTime:new Date,results:[]};this.failoverTests.set(a.id,a),console.log(`Running failover test for plan: ${t.name}`),console.log("This is a non-destructive test using test resources"),console.log("");for(let r of t.runbook.steps){let n=Date.now();console.log(`Testing step ${r.order}: ${r.name}`);let i={step:r.name,status:"success",duration:(Date.now()-n)/1000,message:`Successfully validated step ${r.order}`};a.results.push(i)}return a.status="completed",a.endTime=new Date,a}getDRPlan(e){return this.drPlans.get(e)}listDRPlans(){return Array.from(this.drPlans.values())}getFailoverTest(e){return this.failoverTests.get(e)}listFailoverTests(){return Array.from(this.failoverTests.values())}validateDRPlan(e){let t=[],a=[];if(e.rto<e.rpo)a.push("RTO cannot be less than RPO");if(e.rto>240)t.push("RTO exceeds 4 hours - consider improving recovery time");if(e.rpo>60)t.push("RPO exceeds 1 hour - consider more frequent backups");if(e.resources.length===0)a.push("No resources defined in DR plan");for(let i of e.resources){if(!i.replicationEnabled)t.push(`Resource ${i.resourceId} does not have replication enabled`);if(!i.secondaryArn&&i.resourceType!=="dynamodb")t.push(`Resource ${i.resourceId} does not have secondary resource defined`)}if(e.runbook.steps.length===0)a.push("No recovery steps defined in runbook");let r=e.runbook.steps.reduce((i,s)=>i+s.estimatedDuration,0);if(r>e.rto)t.push(`Estimated recovery duration (${r}m) exceeds RTO (${e.rto}m)`);let n=e.runbook.steps.filter((i)=>!i.automatable);if(n.length>0)t.push(`${n.length} manual steps in runbook - consider automation`);return{valid:a.length===0,warnings:t,errors:a}}clear(){this.drPlans.clear(),this.failoverTests.clear(),this.planCounter=0,this.testCounter=0}}var $d=new vr;class wr{configRules=new Map;configRecorders=new Map;deliveryChannels=new Map;ruleCounter=0;createConfigRecorder(e){return this.configRecorders.set(e.name,e),e}createDeliveryChannel(e){return this.deliveryChannels.set(e.name,e),e}createConfigRule(e){let t=`config-rule-${Date.now()}-${this.ruleCounter++}`,a={id:t,...e};return this.configRules.set(t,a),a}createS3EncryptionRule(){return this.createConfigRule({name:"s3-bucket-server-side-encryption-enabled",description:"Checks that S3 buckets have server-side encryption enabled",source:"AWS_MANAGED",identifier:"S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED",scope:{complianceResourceTypes:["AWS::S3::Bucket"]}})}createS3PublicAccessBlockRule(){return this.createConfigRule({name:"s3-bucket-public-read-prohibited",description:"Checks that S3 buckets do not allow public read access",source:"AWS_MANAGED",identifier:"S3_BUCKET_PUBLIC_READ_PROHIBITED",scope:{complianceResourceTypes:["AWS::S3::Bucket"]}})}createS3VersioningRule(){return this.createConfigRule({name:"s3-bucket-versioning-enabled",description:"Checks whether versioning is enabled for S3 buckets",source:"AWS_MANAGED",identifier:"S3_BUCKET_VERSIONING_ENABLED",scope:{complianceResourceTypes:["AWS::S3::Bucket"]}})}createRdsEncryptionRule(){return this.createConfigRule({name:"rds-storage-encrypted",description:"Checks whether storage encryption is enabled for RDS DB instances",source:"AWS_MANAGED",identifier:"RDS_STORAGE_ENCRYPTED",scope:{complianceResourceTypes:["AWS::RDS::DBInstance"]}})}createRdsSnapshotEncryptionRule(){return this.createConfigRule({name:"rds-snapshots-public-prohibited",description:"Checks if RDS snapshots are public",source:"AWS_MANAGED",identifier:"RDS_SNAPSHOTS_PUBLIC_PROHIBITED",scope:{complianceResourceTypes:["AWS::RDS::DBSnapshot","AWS::RDS::DBClusterSnapshot"]}})}createRdsBackupRule(e=7){return this.createConfigRule({name:"db-backup-enabled",description:"Checks whether RDS DB instances have backups enabled",source:"AWS_MANAGED",identifier:"DB_BACKUP_ENABLED",inputParameters:{backupRetentionPeriod:e},scope:{complianceResourceTypes:["AWS::RDS::DBInstance"]}})}createEc2InstanceProfileRule(){return this.createConfigRule({name:"ec2-instance-managed-by-systems-manager",description:"Checks if EC2 instances are managed by Systems Manager",source:"AWS_MANAGED",identifier:"EC2_INSTANCE_MANAGED_BY_SSM",scope:{complianceResourceTypes:["AWS::EC2::Instance"]}})}createEbsEncryptionRule(){return this.createConfigRule({name:"encrypted-volumes",description:"Checks whether EBS volumes are encrypted",source:"AWS_MANAGED",identifier:"ENCRYPTED_VOLUMES",scope:{complianceResourceTypes:["AWS::EC2::Volume"]}})}createIamPasswordPolicyRule(){return this.createConfigRule({name:"iam-password-policy",description:"Checks whether the IAM password policy meets specified requirements",source:"AWS_MANAGED",identifier:"IAM_PASSWORD_POLICY",inputParameters:{RequireUppercaseCharacters:!0,RequireLowercaseCharacters:!0,RequireSymbols:!0,RequireNumbers:!0,MinimumPasswordLength:14,PasswordReusePrevention:24,MaxPasswordAge:90}})}createIamMfaRule(){return this.createConfigRule({name:"iam-user-mfa-enabled",description:"Checks whether IAM users have MFA enabled",source:"AWS_MANAGED",identifier:"IAM_USER_MFA_ENABLED"})}createRootAccountMfaRule(){return this.createConfigRule({name:"root-account-mfa-enabled",description:"Checks whether the root account has MFA enabled",source:"AWS_MANAGED",identifier:"ROOT_ACCOUNT_MFA_ENABLED"})}createVpcFlowLogsRule(){return this.createConfigRule({name:"vpc-flow-logs-enabled",description:"Checks whether VPC Flow Logs is enabled",source:"AWS_MANAGED",identifier:"VPC_FLOW_LOGS_ENABLED",scope:{complianceResourceTypes:["AWS::EC2::VPC"]}})}createCloudTrailEnabledRule(){return this.createConfigRule({name:"cloudtrail-enabled",description:"Checks whether CloudTrail is enabled",source:"AWS_MANAGED",identifier:"CLOUD_TRAIL_ENABLED",maxExecutionFrequency:"TwentyFour_Hours"})}createCloudWatchAlarmRule(){return this.createConfigRule({name:"cloudwatch-alarm-action-check",description:"Checks whether CloudWatch alarms have actions configured",source:"AWS_MANAGED",identifier:"CLOUDWATCH_ALARM_ACTION_CHECK",inputParameters:{alarmActionRequired:!0,insufficientDataActionRequired:!1,okActionRequired:!1},scope:{complianceResourceTypes:["AWS::CloudWatch::Alarm"]}})}createCustomLambdaRule(e){return this.createConfigRule({name:e.name,description:e.description,source:"CUSTOM_LAMBDA",lambdaFunctionArn:e.lambdaFunctionArn,scope:e.resourceTypes?{complianceResourceTypes:e.resourceTypes}:void 0,maxExecutionFrequency:e.maxExecutionFrequency,inputParameters:e.inputParameters})}createCompliancePreset(e){let t=[];switch(e){case"hipaa":t.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createRdsBackupRule(7),this.createVpcFlowLogsRule());break;case"pci-dss":t.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createIamMfaRule(),this.createRootAccountMfaRule(),this.createVpcFlowLogsRule());break;case"sox":t.push(this.createS3VersioningRule(),this.createCloudTrailEnabledRule(),this.createRdsBackupRule(30),this.createIamPasswordPolicyRule());break;case"gdpr":t.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createRdsSnapshotEncryptionRule());break;case"basic":t.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamMfaRule(),this.createRootAccountMfaRule());break}return t}getConfigRule(e){return this.configRules.get(e)}listConfigRules(){return Array.from(this.configRules.values())}getConfigRecorder(e){return this.configRecorders.get(e)}listConfigRecorders(){return Array.from(this.configRecorders.values())}getDeliveryChannel(e){return this.deliveryChannels.get(e)}listDeliveryChannels(){return Array.from(this.deliveryChannels.values())}generateConfigRuleCF(e){let t={Type:"AWS::Config::ConfigRule",Properties:{ConfigRuleName:e.name,Description:e.description,Source:{Owner:e.source==="AWS_MANAGED"?"AWS":"CUSTOM_LAMBDA"}}};if(e.source==="AWS_MANAGED"&&e.identifier)t.Properties.Source.SourceIdentifier=e.identifier;if(e.source==="CUSTOM_LAMBDA"&&e.lambdaFunctionArn)t.Properties.Source.SourceIdentifier=e.lambdaFunctionArn,t.Properties.Source.SourceDetails=[{EventSource:"aws.config",MessageType:"ConfigurationItemChangeNotification"}];if(e.inputParameters)t.Properties.InputParameters=JSON.stringify(e.inputParameters);if(e.scope){if(t.Properties.Scope={},e.scope.complianceResourceTypes)t.Properties.Scope.ComplianceResourceTypes=e.scope.complianceResourceTypes;if(e.scope.tagKey)t.Properties.Scope.TagKey=e.scope.tagKey;if(e.scope.tagValue)t.Properties.Scope.TagValue=e.scope.tagValue}if(e.maxExecutionFrequency)t.Properties.MaximumExecutionFrequency=e.maxExecutionFrequency;return t}generateConfigRecorderCF(e){return{Type:"AWS::Config::ConfigurationRecorder",Properties:{Name:e.name,RoleArn:e.roleArn,RecordingGroup:e.recordingGroup||{AllSupported:!0,IncludeGlobalResourceTypes:!0}}}}generateDeliveryChannelCF(e){return{Type:"AWS::Config::DeliveryChannel",Properties:{Name:e.name,S3BucketName:e.s3BucketName,...e.s3KeyPrefix&&{S3KeyPrefix:e.s3KeyPrefix},...e.snsTopicArn&&{SnsTopicARN:e.snsTopicArn},...e.configSnapshotDeliveryProperties&&{ConfigSnapshotDeliveryProperties:e.configSnapshotDeliveryProperties}}}}clear(){this.configRules.clear(),this.configRecorders.clear(),this.deliveryChannels.clear(),this.ruleCounter=0}}var Yd=new wr;class Er{trails=new Map;trailCounter=0;createTrail(e){let t=`trail-${Date.now()}-${this.trailCounter++}`,a={id:t,...e};return this.trails.set(t,a),a}createOrganizationTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,s3KeyPrefix:"organization-trail",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:e.kmsKeyId,cloudWatchLogsLogGroupArn:e.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:e.cloudWatchLogsRoleArn})}createSecurityAuditTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,s3KeyPrefix:"security-audit",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:e.kmsKeyId,cloudWatchLogsLogGroupArn:e.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:e.cloudWatchLogsRoleArn,eventSelectors:[{readWriteType:"All",includeManagementEvents:!0,excludeManagementEventSources:[]}],insightSelectors:[{insightType:"ApiCallRateInsight"},{insightType:"ApiErrorRateInsight"}]})}createDataEventsTrail(e){let t=[];if(e.s3DataBuckets&&e.s3DataBuckets.length>0)t.push({type:"AWS::S3::Object",values:e.s3DataBuckets.map((a)=>`arn:aws:s3:::${a}/*`)});if(e.lambdaFunctions&&e.lambdaFunctions.length>0)t.push({type:"AWS::Lambda::Function",values:e.lambdaFunctions});return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,s3KeyPrefix:"data-events",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"All",includeManagementEvents:!1,dataResources:t}]})}createAdvancedTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,advancedEventSelectors:e.selectors})}createReadOnlyTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"ReadOnly",includeManagementEvents:!0}]})}createWriteOnlyTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"WriteOnly",includeManagementEvents:!0}]})}getTrail(e){return this.trails.get(e)}listTrails(){return Array.from(this.trails.values())}generateTrailCF(e){let t={Type:"AWS::CloudTrail::Trail",Properties:{TrailName:e.name,S3BucketName:e.s3BucketName,IsLogging:!0,IncludeGlobalServiceEvents:e.includeGlobalServiceEvents??!0,IsMultiRegionTrail:e.isMultiRegionTrail??!0,EnableLogFileValidation:e.enableLogFileValidation??!0}};if(e.s3KeyPrefix)t.Properties.S3KeyPrefix=e.s3KeyPrefix;if(e.cloudWatchLogsLogGroupArn)t.Properties.CloudWatchLogsLogGroupArn=e.cloudWatchLogsLogGroupArn;if(e.cloudWatchLogsRoleArn)t.Properties.CloudWatchLogsRoleArn=e.cloudWatchLogsRoleArn;if(e.snsTopicName)t.Properties.SnsTopicName=e.snsTopicName;if(e.kmsKeyId)t.Properties.KMSKeyId=e.kmsKeyId;if(e.eventSelectors)t.Properties.EventSelectors=e.eventSelectors.map((a)=>({ReadWriteType:a.readWriteType,IncludeManagementEvents:a.includeManagementEvents??!0,...a.dataResources&&{DataResources:a.dataResources.map((r)=>({Type:r.type,Values:r.values}))},...a.excludeManagementEventSources&&{ExcludeManagementEventSources:a.excludeManagementEventSources}}));if(e.insightSelectors)t.Properties.InsightSelectors=e.insightSelectors.map((a)=>({InsightType:a.insightType}));if(e.advancedEventSelectors)t.Properties.AdvancedEventSelectors=e.advancedEventSelectors.map((a)=>({Name:a.name,FieldSelectors:a.fieldSelectors.map((r)=>({Field:r.field,...r.equals&&{Equals:r.equals},...r.startsWith&&{StartsWith:r.startsWith},...r.endsWith&&{EndsWith:r.endsWith},...r.notEquals&&{NotEquals:r.notEquals},...r.notStartsWith&&{NotStartsWith:r.notStartsWith},...r.notEndsWith&&{NotEndsWith:r.notEndsWith}}))}));return t}generateBucketPolicy(e,t){return{Version:"2012-10-17",Statement:[{Sid:"AWSCloudTrailAclCheck",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:GetBucketAcl",Resource:`arn:aws:s3:::${e}`},{Sid:"AWSCloudTrailWrite",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:PutObject",Resource:t.map((a)=>`arn:aws:s3:::${e}/AWSLogs/${a}/*`),Condition:{StringEquals:{"s3:x-amz-acl":"bucket-owner-full-control"}}}]}}clear(){this.trails.clear(),this.trailCounter=0}}var Xd=new Er;class Pr{detectors=new Map;threatIntelSets=new Map;ipSets=new Map;filters=new Map;detectorCounter=0;threatIntelCounter=0;ipSetCounter=0;filterCounter=0;createDetector(e){let t=`detector-${Date.now()}-${this.detectorCounter++}`,a={id:t,...e};return this.detectors.set(t,a),a}createComprehensiveDetector(){return this.createDetector({enable:!0,findingPublishingFrequency:"FIFTEEN_MINUTES",dataSources:{s3Logs:{enable:!0},kubernetes:{auditLogs:{enable:!0}},malwareProtection:{scanEc2InstanceWithFindings:{ebsVolumes:{enable:!0}}}},features:[{name:"S3_DATA_EVENTS",status:"ENABLED"},{name:"EKS_AUDIT_LOGS",status:"ENABLED"},{name:"EBS_MALWARE_PROTECTION",status:"ENABLED"},{name:"RDS_LOGIN_EVENTS",status:"ENABLED"},{name:"LAMBDA_NETWORK_LOGS",status:"ENABLED"}]})}createBasicDetector(){return this.createDetector({enable:!0,findingPublishingFrequency:"SIX_HOURS"})}createThreatIntelSet(e){let t=`threat-intel-${Date.now()}-${this.threatIntelCounter++}`,a={id:t,...e};return this.threatIntelSets.set(t,a),a}createIPSet(e){let t=`ip-set-${Date.now()}-${this.ipSetCounter++}`,a={id:t,...e};return this.ipSets.set(t,a),a}createFindingFilter(e){let t=`filter-${Date.now()}-${this.filterCounter++}`,a={id:t,...e};return this.filters.set(t,a),a}createLowSeverityArchiveFilter(e){return this.createFindingFilter({detectorId:e,name:"archive-low-severity",description:"Automatically archive low severity findings",action:"ARCHIVE",rank:1,findingCriteria:{criterion:{severity:{lt:4}}}})}createFindingTypeFilter(e,t,a){return this.createFindingFilter({detectorId:e,name:`filter-finding-types-${a.toLowerCase()}`,description:`${a==="ARCHIVE"?"Archive":"Keep"} specific finding types`,action:a,rank:2,findingCriteria:{criterion:{type:{eq:t}}}})}createTrustedIPFilter(e,t){return this.createFindingFilter({detectorId:e,name:"trusted-ip-addresses",description:"Archive findings from trusted IP addresses",action:"ARCHIVE",rank:3,findingCriteria:{criterion:{"resource.instanceDetails.networkInterfaces.privateIpAddress":{eq:t}}}})}getDetector(e){return this.detectors.get(e)}listDetectors(){return Array.from(this.detectors.values())}getThreatIntelSet(e){return this.threatIntelSets.get(e)}listThreatIntelSets(){return Array.from(this.threatIntelSets.values())}getIPSet(e){return this.ipSets.get(e)}listIPSets(){return Array.from(this.ipSets.values())}getFindingFilter(e){return this.filters.get(e)}listFindingFilters(){return Array.from(this.filters.values())}generateDetectorCF(e){let t={Type:"AWS::GuardDuty::Detector",Properties:{Enable:e.enable}};if(e.findingPublishingFrequency)t.Properties.FindingPublishingFrequency=e.findingPublishingFrequency;if(e.dataSources){if(t.Properties.DataSources={},e.dataSources.s3Logs)t.Properties.DataSources.S3Logs={Enable:e.dataSources.s3Logs.enable};if(e.dataSources.kubernetes)t.Properties.DataSources.Kubernetes={AuditLogs:{Enable:e.dataSources.kubernetes.auditLogs.enable}};if(e.dataSources.malwareProtection)t.Properties.DataSources.MalwareProtection={ScanEc2InstanceWithFindings:{EbsVolumes:{Enable:e.dataSources.malwareProtection.scanEc2InstanceWithFindings.ebsVolumes.enable}}}}if(e.features)t.Properties.Features=e.features.map((a)=>({Name:a.name,Status:a.status,...a.additionalConfiguration&&{AdditionalConfiguration:a.additionalConfiguration}}));return t}generateThreatIntelSetCF(e){return{Type:"AWS::GuardDuty::ThreatIntelSet",Properties:{DetectorId:e.detectorId,Name:e.name,Format:e.format,Location:e.location,Activate:e.activate}}}generateIPSetCF(e){return{Type:"AWS::GuardDuty::IPSet",Properties:{DetectorId:e.detectorId,Name:e.name,Format:e.format,Location:e.location,Activate:e.activate}}}generateFilterCF(e){return{Type:"AWS::GuardDuty::Filter",Properties:{DetectorId:e.detectorId,Name:e.name,Description:e.description,Action:e.action,Rank:e.rank,FindingCriteria:{Criterion:e.findingCriteria.criterion}}}}clear(){this.detectors.clear(),this.threatIntelSets.clear(),this.ipSets.clear(),this.filters.clear(),this.detectorCounter=0,this.threatIntelCounter=0,this.ipSetCounter=0,this.filterCounter=0}}var Zd=new Pr;class xe{hubs=new Map;hubCounter=0;ruleCounter=0;static Standards={AWS_FOUNDATIONAL_SECURITY:{arn:"arn:aws:securityhub:::ruleset/aws-foundational-security-best-practices/v/1.0.0",name:"AWS Foundational Security Best Practices",description:"AWS recommended security best practices"},CIS_AWS_FOUNDATIONS_1_2:{arn:"arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0",name:"CIS AWS Foundations Benchmark v1.2.0",description:"CIS AWS Foundations Benchmark v1.2.0"},CIS_AWS_FOUNDATIONS_1_4:{arn:"arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.4.0",name:"CIS AWS Foundations Benchmark v1.4.0",description:"CIS AWS Foundations Benchmark v1.4.0"},PCI_DSS:{arn:"arn:aws:securityhub:us-east-1::standards/pci-dss/v/3.2.1",name:"PCI DSS v3.2.1",description:"Payment Card Industry Data Security Standard"},NIST_800_53:{arn:"arn:aws:securityhub:us-east-1::standards/nist-800-53/v/5.0.0",name:"NIST SP 800-53 Rev. 5",description:"NIST Special Publication 800-53 Revision 5"}};createHub(e){let t=`hub-${Date.now()}-${this.hubCounter++}`,a={id:t,...e};return this.hubs.set(t,a),a}createComprehensiveHub(){return this.createHub({enable:!0,controlFindingGenerator:"SECURITY_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...xe.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...xe.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...xe.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...xe.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0}]})}createLowSeveritySuppressionRule(){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:"Suppress Low Severity Informational Findings",description:"Automatically suppress informational findings",actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"SUPPRESSED"},note:{text:"Automatically suppressed low severity finding",updatedBy:"SecurityHub Automation"}}}],criteria:{severityLabel:[{value:"INFORMATIONAL",comparison:"EQUALS"}],recordState:[{value:"ACTIVE",comparison:"EQUALS"}]},ruleStatus:"ENABLED",ruleOrder:1}}createResourceTypeNotificationRule(e){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:"Notify on Critical Resource Findings",description:"Set findings for critical resources to NOTIFIED status",actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"NOTIFIED"},note:{text:"Critical resource finding requires attention",updatedBy:"SecurityHub Automation"}}}],criteria:{resourceType:e.map((t)=>({value:t,comparison:"EQUALS"})),severityLabel:[{value:"HIGH",comparison:"EQUALS"},{value:"CRITICAL",comparison:"EQUALS"}],workflowStatus:[{value:"NEW",comparison:"EQUALS"}]},ruleStatus:"ENABLED",ruleOrder:2}}createComplianceFailureRule(){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:"Flag Compliance Failures",description:"Increase severity for compliance failures",actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{severity:{label:"HIGH"},workflow:{status:"NOTIFIED"},note:{text:"Compliance failure detected - requires immediate attention",updatedBy:"SecurityHub Automation"}}}],criteria:{complianceStatus:[{value:"FAILED",comparison:"EQUALS"}],recordState:[{value:"ACTIVE",comparison:"EQUALS"}]},ruleStatus:"ENABLED",ruleOrder:3}}createFalsePositiveSuppressionRule(e,t){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:`Suppress False Positives - ${e}`,description:`Automatically suppress known false positives from ${e}`,actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"SUPPRESSED"},note:{text:"Known false positive - automatically suppressed",updatedBy:"SecurityHub Automation"}}}],criteria:{productName:[{value:e,comparison:"EQUALS"}],title:t.map((a)=>({value:a,comparison:"PREFIX"}))},ruleStatus:"ENABLED",ruleOrder:10}}getHub(e){return this.hubs.get(e)}listHubs(){return Array.from(this.hubs.values())}generateHubCF(e){let t={Type:"AWS::SecurityHub::Hub",Properties:{}};if(e.controlFindingGenerator)t.Properties.ControlFindingGenerator=e.controlFindingGenerator;if(e.enableDefaultStandards!==void 0)t.Properties.EnableDefaultStandards=e.enableDefaultStandards;return t}generateStandardCF(e){let t={Type:"AWS::SecurityHub::Standard",Properties:{StandardsArn:e.arn}};if(e.disabledControls&&e.disabledControls.length>0)t.Properties.DisabledStandardsControls=e.disabledControls.map((a)=>({StandardsControlArn:a,Reason:"Disabled by configuration"}));return t}generateAutomationRuleCF(e){return{Type:"AWS::SecurityHub::AutomationRule",Properties:{RuleName:e.ruleName,Description:e.description,Actions:e.actions.map((t)=>({Type:t.type,FindingFieldsUpdate:t.findingFieldsUpdate})),Criteria:e.criteria,RuleStatus:e.ruleStatus,RuleOrder:e.ruleOrder}}}clear(){this.hubs.clear(),this.hubCounter=0,this.ruleCounter=0}}var em=new xe;class Ir{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;createDeployment(e){let t=`bg-deployment-${Date.now()}-${this.deploymentCounter++}`,a={id:t,...e};return this.deployments.set(t,a),a}createALBDeployment(e){return this.createDeployment({name:e.name,blueEnvironment:{name:"blue",targetGroupArn:e.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:e.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:e.listenerArn,switchoverTimeSeconds:0},autoPromote:e.autoPromote,healthCheckConfig:e.healthCheckConfig})}createRoute53Deployment(e){return this.createDeployment({name:e.name,blueEnvironment:{name:"blue",targetGroupArn:e.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:e.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"route53",hostedZoneId:e.hostedZoneId,switchoverTimeSeconds:e.switchoverTimeSeconds||60}})}createECSDeployment(e){return this.createDeployment({name:e.name,blueEnvironment:{name:"blue",targetGroupArn:e.blueTargetGroupArn,taskDefinitionArn:e.blueTaskDefinitionArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:e.greenTargetGroupArn,taskDefinitionArn:e.greenTaskDefinitionArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:e.listenerArn},autoRollback:e.autoRollback??!0})}async executeDeployment(e,t=!1){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);let r={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!1,errors:[]};console.log(`${t?"[DRY RUN] ":""}Starting blue/green deployment: ${a.name}`),console.log(` Active environment: ${a.activeEnvironment}`),console.log(` Routing type: ${a.routingConfig.type}`);let n=a.activeEnvironment==="blue"?"green":"blue";if(console.log(` Switching to: ${n}`),console.log(`\\n1. Deploying to ${n} environment`),!t)await new Promise((i)=>setTimeout(i,100));if(console.log(`\\n2. Running health checks on ${n} environment`),a.healthCheckConfig){let i=await this.runHealthChecks(a,n,t);if(r.healthChecksPassed=i,!i){if(r.errors?.push("Health checks failed"),r.endTime=new Date,a.autoRollback)console.log(" Auto-rollback enabled - keeping current environment active"),r.rolledBackAt=new Date;return this.recordDeployment(e,r),r}}else r.healthChecksPassed=!0;if(console.log(`\\n3. Switching traffic to ${n} environment`),!t)a.activeEnvironment=n,r.switchedAt=new Date;if(console.log(`\\n4. Monitoring ${n} environment`),!t)await new Promise((i)=>setTimeout(i,100));return r.success=!0,r.endTime=new Date,console.log("\\n✓ Deployment completed successfully"),this.recordDeployment(e,r),r}async rollback(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);let a={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!0,errors:[]};console.log(`Rolling back deployment: ${t.name}`);let r=t.activeEnvironment==="blue"?"green":"blue";return t.activeEnvironment=r,a.success=!0,a.rolledBackAt=new Date,a.endTime=new Date,console.log(` Switched back to: ${r}`),this.recordDeployment(e,a),a}async runHealthChecks(e,t,a){let r=e.healthCheckConfig;if(console.log(` Health check path: ${r.path||"/"}`),console.log(` Healthy threshold: ${r.healthyThreshold}`),console.log(` Interval: ${r.interval}s`),a)return console.log(" [SKIPPED - DRY RUN]"),!0;let n=0,i=r.healthyThreshold+2;for(let s=0;s<i;s++)if(await new Promise((o)=>setTimeout(o,50)),Math.random()>0.1){if(n++,console.log(` Check ${s+1}: ✓ Healthy (${n}/${r.healthyThreshold})`),n>=r.healthyThreshold)return!0}else n=0,console.log(` Check ${s+1}: ✗ Unhealthy`);return!1}recordDeployment(e,t){if(!this.deploymentHistory.has(e))this.deploymentHistory.set(e,[]);this.deploymentHistory.get(e).push(t)}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(e){return this.deploymentHistory.get(e)||[]}generateALBListenerCF(e){let t=e.activeEnvironment==="blue"?e.blueEnvironment:e.greenEnvironment;return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:e.routingConfig.listenerArn,Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",TargetGroupArn:t.targetGroupArn}]}}}generateRoute53RecordSetCF(e,t){return[{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.routingConfig.hostedZoneId,Name:t,Type:"A",SetIdentifier:"blue",Weight:e.activeEnvironment==="blue"?100:0,AliasTarget:{HostedZoneId:e.routingConfig.hostedZoneId,DNSName:e.blueEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}},{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.routingConfig.hostedZoneId,Name:t,Type:"A",SetIdentifier:"green",Weight:e.activeEnvironment==="green"?100:0,AliasTarget:{HostedZoneId:e.routingConfig.hostedZoneId,DNSName:e.greenEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}}]}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var tm=new Ir;class At{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;static Strategies={CONSERVATIVE:[{name:"Initial Canary",trafficPercentage:10,durationMinutes:10},{name:"Quarter Traffic",trafficPercentage:25,durationMinutes:10},{name:"Half Traffic",trafficPercentage:50,durationMinutes:15},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}],BALANCED:[{name:"Initial Canary",trafficPercentage:20,durationMinutes:5},{name:"Half Traffic",trafficPercentage:50,durationMinutes:10},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}],AGGRESSIVE:[{name:"Half Traffic",trafficPercentage:50,durationMinutes:5},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}],LINEAR_10:[{name:"Canary 10%",trafficPercentage:10,durationMinutes:5},{name:"Canary 20%",trafficPercentage:20,durationMinutes:5},{name:"Canary 30%",trafficPercentage:30,durationMinutes:5},{name:"Canary 40%",trafficPercentage:40,durationMinutes:5},{name:"Canary 50%",trafficPercentage:50,durationMinutes:5},{name:"Canary 60%",trafficPercentage:60,durationMinutes:5},{name:"Canary 70%",trafficPercentage:70,durationMinutes:5},{name:"Canary 80%",trafficPercentage:80,durationMinutes:5},{name:"Canary 90%",trafficPercentage:90,durationMinutes:5},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}]};createDeployment(e){let t=`canary-${Date.now()}-${this.deploymentCounter++}`,a={id:t,...e};return this.deployments.set(t,a),a}createLambdaCanaryDeployment(e){let t=e.strategy||"BALANCED",a=At.Strategies[t].map((r)=>({...r,alarmThresholds:{errorRate:e.errorRateThreshold||1,latencyP99:e.latencyThreshold||1000}}));return this.createDeployment({name:e.name,baselineVersion:{version:"baseline",functionVersionArn:e.baselineVersionArn,weight:100},canaryVersion:{version:"canary",functionVersionArn:e.canaryVersionArn,weight:0},stages:a,currentStage:0,status:"pending",autoPromote:e.autoPromote??!0,autoRollback:!0})}createECSCanaryDeployment(e){let t=e.strategy||"CONSERVATIVE",a=At.Strategies[t];return this.createDeployment({name:e.name,baselineVersion:{version:"baseline",taskDefinitionArn:e.baselineTaskDefinitionArn,targetGroupArn:e.baselineTargetGroupArn,weight:100},canaryVersion:{version:"canary",taskDefinitionArn:e.canaryTaskDefinitionArn,targetGroupArn:e.canaryTargetGroupArn,weight:0},stages:a,currentStage:0,status:"pending",autoRollback:!0})}async executeDeployment(e,t=!1){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);let r={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,completedStages:0,rolledBack:!1};console.log(`${t?"[DRY RUN] ":""}Starting canary deployment: ${a.name}`),console.log(` Strategy: ${a.stages.length} stages`),console.log(` Auto-promote: ${a.autoPromote}`),console.log(` Auto-rollback: ${a.autoRollback}`),console.log(""),a.status="in_progress";for(let n=0;n<a.stages.length;n++){let i=a.stages[n];if(a.currentStage=n,console.log(`Stage ${n+1}/${a.stages.length}: ${i.name}`),console.log(` Traffic: ${i.trafficPercentage}% canary, ${100-i.trafficPercentage}% baseline`),console.log(` Duration: ${i.durationMinutes} minutes`),!t)a.baselineVersion.weight=100-i.trafficPercentage,a.canaryVersion.weight=i.trafficPercentage;if(!await this.monitorStage(a,i,t)){if(console.log(" ✗ Stage failed - metrics exceeded thresholds"),a.autoRollback)console.log("\\n Rolling back deployment..."),await this.rollback(e,t),r.rolledBack=!0,r.reason="Metrics exceeded thresholds";return r.endTime=new Date,a.status="rolled_back",this.recordDeployment(e,r),r}console.log(" ✓ Stage completed successfully"),r.completedStages++,console.log("")}return a.status="completed",r.success=!0,r.endTime=new Date,console.log("✓ Canary deployment completed successfully"),this.recordDeployment(e,r),r}async monitorStage(e,t,a){if(console.log(" Monitoring metrics..."),a)return console.log(" [SKIPPED - DRY RUN]"),!0;await new Promise((n)=>setTimeout(n,100));let r={baselineErrorRate:Math.random()*0.5,canaryErrorRate:Math.random()*0.8,baselineLatencyP99:200+Math.random()*100,canaryLatencyP99:180+Math.random()*150,baselineRequestCount:Math.floor(Math.random()*1000)+500,canaryRequestCount:Math.floor((Math.random()*1000+500)*t.trafficPercentage/100)};if(e.metrics=r,console.log(` Baseline: ${r.baselineErrorRate.toFixed(2)}% errors, ${r.baselineLatencyP99.toFixed(0)}ms P99`),console.log(` Canary: ${r.canaryErrorRate.toFixed(2)}% errors, ${r.canaryLatencyP99.toFixed(0)}ms P99`),t.alarmThresholds){let{errorRate:n,latencyP99:i}=t.alarmThresholds;if(n&&r.canaryErrorRate>n)return console.log(` ⚠ Error rate exceeded threshold: ${r.canaryErrorRate.toFixed(2)}% > ${n}%`),!1;if(i&&r.canaryLatencyP99>i)return console.log(` ⚠ Latency P99 exceeded threshold: ${r.canaryLatencyP99.toFixed(0)}ms > ${i}ms`),!1}return!0}async rollback(e,t=!1){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);if(console.log(`${t?"[DRY RUN] ":""}Rolling back canary deployment: ${a.name}`),!t)a.baselineVersion.weight=100,a.canaryVersion.weight=0,a.status="rolled_back";console.log(" Traffic restored to baseline: 100%")}promoteCanary(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);console.log(`Promoting canary to baseline: ${t.name}`);let a=t.baselineVersion;t.baselineVersion=t.canaryVersion,t.canaryVersion=a,t.baselineVersion.weight=100,t.canaryVersion.weight=0,t.status="completed",console.log(" Canary promoted successfully")}recordDeployment(e,t){if(!this.deploymentHistory.has(e))this.deploymentHistory.set(e,[]);this.deploymentHistory.get(e).push(t)}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(e){return this.deploymentHistory.get(e)||[]}generateLambdaAliasCF(e,t){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:{Ref:"LambdaFunction"},Name:t,FunctionVersion:e.canaryVersion.version,RoutingConfig:{AdditionalVersionWeights:[{FunctionVersion:e.baselineVersion.version,FunctionWeight:e.baselineVersion.weight/100}]}}}}generateALBListenerRuleCF(e){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:[{TargetGroupArn:e.baselineVersion.targetGroupArn,Weight:e.baselineVersion.weight},{TargetGroupArn:e.canaryVersion.targetGroupArn,Weight:e.canaryVersion.weight}],TargetGroupStickinessConfig:{Enabled:!1}}}]}}}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var am=new At;class Rr{tests=new Map;testCounter=0;createTest(e){let t=`abtest-${Date.now()}-${this.testCounter++}`,a={id:t,...e};return this.tests.set(t,a),a}createSimpleABTest(e){let t=e.variantTrafficPercentage||50;return this.createTest({name:e.name,description:e.description,variants:[{id:"control",name:"Control",description:"Original version",trafficPercentage:100-t,targetGroupArn:e.controlTargetGroupArn,weight:100-t},{id:"variant-a",name:"Variant A",description:"Test version",trafficPercentage:t,targetGroupArn:e.variantTargetGroupArn,weight:t}],routingStrategy:{type:e.stickySession?"cookie":"random",cookieName:e.stickySession?"ab_variant":void 0,stickySession:e.stickySession??!1,sessionDuration:1440},startTime:new Date,status:"draft"})}createMultivariateTest(e){let t=e.variants.reduce((a,r)=>a+r.trafficPercentage,0);if(t!==100)throw Error(`Traffic percentages must sum to 100, got ${t}`);return this.createTest({name:e.name,description:e.description,variants:e.variants.map((a,r)=>({id:`variant-${r}`,name:a.name,description:a.description,trafficPercentage:a.trafficPercentage,targetGroupArn:a.targetGroupArn,weight:a.trafficPercentage})),routingStrategy:e.routingStrategy||{type:"random",stickySession:!1},startTime:new Date,status:"draft"})}createHeaderBasedTest(e){return this.createTest({name:e.name,description:`Route based on ${e.headerName} header`,variants:[{id:"control",name:"Control",trafficPercentage:50,targetGroupArn:e.controlTargetGroupArn,weight:50},{id:"variant-a",name:"Variant A",trafficPercentage:50,targetGroupArn:e.variantTargetGroupArn,weight:50}],routingStrategy:{type:"header",headerName:e.headerName,stickySession:!1},startTime:new Date,status:"draft"})}createGeoBasedTest(e){return this.createTest({name:e.name,description:"Route based on geographic location",variants:[{id:"control",name:"Control (Rest of World)",trafficPercentage:50,targetGroupArn:e.controlTargetGroupArn,weight:50},{id:"variant-a",name:`Variant A (${e.regions.join(", ")})`,trafficPercentage:50,targetGroupArn:e.variantTargetGroupArn,weight:50}],routingStrategy:{type:"geo",stickySession:!0,sessionDuration:1440},startTime:new Date,status:"draft"})}startTest(e){let t=this.tests.get(e);if(!t)throw Error(`Test not found: ${e}`);if(t.status!=="draft"&&t.status!=="paused")throw Error(`Cannot start test in ${t.status} status`);t.status="active",t.startTime=new Date,console.log(`Started A/B test: ${t.name}`),console.log(` Variants: ${t.variants.length}`),t.variants.forEach((a)=>{console.log(` - ${a.name}: ${a.trafficPercentage}%`)})}pauseTest(e){let t=this.tests.get(e);if(!t)throw Error(`Test not found: ${e}`);t.status="paused",console.log(`Paused A/B test: ${t.name}`)}updateTrafficSplit(e,t,a){let r=this.tests.get(e);if(!r)throw Error(`Test not found: ${e}`);let n=r.variants.find((s)=>s.id===t);if(!n)throw Error(`Variant not found: ${t}`);let i=n.trafficPercentage;n.trafficPercentage=a,n.weight=a,console.log(`Updated ${n.name} traffic: ${i}% → ${a}%`)}analyzeResults(e){let t=this.tests.get(e);if(!t)throw Error(`Test not found: ${e}`);if(!t.metrics)t.metrics=this.collectMetrics(t);let a=t.variants[0],r=0;for(let l of t.variants){let u=t.metrics.variants[l.id];if(u&&u.conversionRate>r)r=u.conversionRate,a=l}let n=t.metrics.variants.control||t.metrics.variants[t.variants[0].id],i=t.metrics.variants[a.id],s=(i.conversionRate-n.conversionRate)/n.conversionRate*100,o=100,c=i.requests>o&&n.requests>o&&Math.abs(s)>10;return{testId:e,winningVariant:a.name,confidence:c?95:75,improvement:s,statisticalSignificance:c,metrics:t.metrics,recommendation:this.generateRecommendation(s,c,a.name)}}declareWinner(e,t){let a=this.tests.get(e);if(!a)throw Error(`Test not found: ${e}`);let r=a.variants.find((n)=>n.id===t);if(!r)throw Error(`Variant not found: ${t}`);a.variants.forEach((n)=>{if(n.id===t)n.trafficPercentage=100,n.weight=100;else n.trafficPercentage=0,n.weight=0}),a.status="completed",a.endTime=new Date,a.winner=t,console.log(`Declared winner: ${r.name}`),console.log(` All traffic now routed to ${r.name}`)}collectMetrics(e){let t={},a=0;for(let r of e.variants){let n=Math.floor(Math.random()*1000)+500,i=Math.floor(n*(Math.random()*0.1+0.05)),s=i/n*100;t[r.id]={requests:n,conversions:i,conversionRate:s,averageLatency:150+Math.random()*100,errorRate:Math.random()*0.5,revenue:i*(Math.random()*50+100)},a+=n}return{variants:t,totalRequests:a,startTime:e.startTime,lastUpdated:new Date}}generateRecommendation(e,t,a){if(!t)return"Continue test - sample size too small or no significant difference detected";if(e>20)return`Strong winner detected - ${a} shows ${e.toFixed(1)}% improvement. Recommend deploying to all traffic.`;if(e>10)return`Moderate improvement - ${a} shows ${e.toFixed(1)}% improvement. Consider deploying.`;if(e>0)return`Minor improvement - ${a} shows ${e.toFixed(1)}% improvement. May not be worth the complexity.`;return"No improvement detected - consider reverting to control variant"}getTest(e){return this.tests.get(e)}listTests(){return Array.from(this.tests.values())}generateALBListenerRuleCF(e){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:e.variants.map((t)=>({TargetGroupArn:t.targetGroupArn,Weight:t.weight})),TargetGroupStickinessConfig:{Enabled:e.routingStrategy.stickySession||!1,DurationSeconds:e.routingStrategy.sessionDuration?e.routingStrategy.sessionDuration*60:void 0}}}]}}}generateLambdaEdgeFunction(e){return`'use strict';
|
|
3600
|
+
`}class vr{backupPlans=new Map;backupVaults=new Map;restoreJobs=new Map;continuousBackups=new Map;planCounter=0;restoreCounter=0;continuousBackupCounter=0;createVault(e){this.backupVaults.set(e.name,e)}getVault(e){return this.backupVaults.get(e)}createBackupPlan(e){let t=`backup-plan-${Date.now()}-${this.planCounter++}`,a={id:t,...e};return this.backupPlans.set(t,a),a}getBackupPlan(e){return this.backupPlans.get(e)}listBackupPlans(){return Array.from(this.backupPlans.values())}createRDSBackupPlan(e){let{dbInstanceArn:t,schedule:a="0 2 * * *",retentionDays:r=7,vaultName:n="default-vault"}=e;return this.createBackupPlan({name:"RDS Daily Backup",schedule:a,retentionDays:r,vaultName:n,resources:[{resourceArn:t,resourceType:"rds",region:"us-east-1"}],lifecycle:{moveTocoldStorageAfterDays:30,deleteAfterDays:r}})}createDynamoDBBackupPlan(e){let{tableArn:t,schedule:a="0 3 * * *",retentionDays:r=35,crossRegionCopy:n}=e;return this.createBackupPlan({name:"DynamoDB Daily Backup",schedule:a,retentionDays:r,vaultName:"dynamodb-vault",resources:[{resourceArn:t,resourceType:"dynamodb",region:"us-east-1"}],lifecycle:{deleteAfterDays:r},tags:n?{CrossRegionCopy:n.join(",")}:void 0})}createEFSBackupPlan(e){let{fileSystemArn:t,schedule:a="0 1 * * *",retentionDays:r=30}=e;return this.createBackupPlan({name:"EFS Daily Backup",schedule:a,retentionDays:r,vaultName:"efs-vault",resources:[{resourceArn:t,resourceType:"efs",region:"us-east-1"}],lifecycle:{deleteAfterDays:r}})}enableContinuousBackup(e,t=35){let a=`continuous-backup-${Date.now()}-${this.continuousBackupCounter++}`,r={id:a,resourceId:e,enabled:!0,retentionDays:t};return this.continuousBackups.set(a,r),r}getContinuousBackup(e){return this.continuousBackups.get(e)}enablePointInTimeRecovery(e,t){return{enabled:!0,earliestRestorableTime:new Date(Date.now()-604800000),latestRestorableTime:new Date}}async restoreFromBackup(e){let{backupId:t,resourceType:a,targetRegion:r}=e,n={id:`restore-${Date.now()}-${this.restoreCounter++}`,backupId:t,resourceType:a,status:"pending",startTime:new Date,targetRegion:r};return this.restoreJobs.set(n.id,n),setTimeout(()=>{n.status="running"},100),setTimeout(()=>{n.status="completed",n.endTime=new Date},1000),n}async restoreToPointInTime(e){let{sourceResourceArn:t,targetResourceName:a,restoreTime:r,resourceType:n}=e,i={id:`pitr-${Date.now()}-${this.restoreCounter++}`,backupId:`pitr-${r.getTime()}`,resourceType:n,status:"pending",startTime:new Date};return this.restoreJobs.set(i.id,i),console.log(`Restoring ${n} from ${t} to ${a} at ${r.toISOString()}`),setTimeout(()=>{i.status="completed",i.endTime=new Date},2000),i}getRestoreJob(e){return this.restoreJobs.get(e)}listRestoreJobs(){return Array.from(this.restoreJobs.values())}setupCrossRegionReplication(e){let{sourceVault:t,sourceRegion:a,targetRegions:r}=e;console.log("Setting up cross-region replication:"),console.log(` Source: ${t} in ${a}`),console.log(` Targets: ${r.join(", ")}`)}generateBackupVaultCF(e){return{Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:e.name,...e.encryptionKeyArn&&{EncryptionKeyArn:e.encryptionKeyArn},...e.accessPolicy&&{AccessPolicy:e.accessPolicy}}}}generateBackupPlanCF(e){return{Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:e.name,BackupPlanRule:[{RuleName:"DailyBackup",TargetBackupVault:e.vaultName,ScheduleExpression:`cron(${e.schedule})`,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:e.lifecycle?{...e.lifecycle.moveTocoldStorageAfterDays&&{MoveToColdStorageAfterDays:e.lifecycle.moveTocoldStorageAfterDays},...e.lifecycle.deleteAfterDays&&{DeleteAfterDays:e.lifecycle.deleteAfterDays}}:void 0}]},...e.tags&&{BackupPlanTags:e.tags}}}}generateBackupSelectionCF(e){return{Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:{Ref:`BackupPlan${e.id}`},BackupSelection:{SelectionName:`${e.name}Selection`,IamRoleArn:"arn:aws:iam::123456789012:role/service-role/AWSBackupDefaultServiceRole",Resources:e.resources.map((t)=>t.resourceArn)}}}}clear(){this.backupPlans.clear(),this.backupVaults.clear(),this.restoreJobs.clear(),this.continuousBackups.clear(),this.planCounter=0,this.restoreCounter=0,this.continuousBackupCounter=0}}var Jd=new vr;class wr{drPlans=new Map;failoverTests=new Map;planCounter=0;testCounter=0;createDRPlan(e){let t=`dr-plan-${Date.now()}-${this.planCounter++}`,a={id:t,...e};return this.drPlans.set(t,a),a}createRDSDRPlan(e){let{primaryDbArn:t,secondaryDbArn:a,primaryRegion:r,secondaryRegion:n,rto:i=60,rpo:s=5}=e;return this.createDRPlan({name:"RDS Multi-Region DR",primaryRegion:r,secondaryRegion:n,rto:i,rpo:s,resources:[{resourceId:"primary-db",resourceType:"rds",primaryArn:t,secondaryArn:a,replicationEnabled:!0}],runbook:this.generateRDSRunbook(r,n),testSchedule:"0 0 1 * *"})}createDynamoDBDRPlan(e){let{tableArn:t,regions:a,rto:r=15,rpo:n=1}=e;return this.createDRPlan({name:"DynamoDB Global Tables DR",primaryRegion:a[0],secondaryRegion:a[1],rto:r,rpo:n,resources:[{resourceId:"dynamodb-table",resourceType:"dynamodb",primaryArn:t,replicationEnabled:!0}],runbook:this.generateDynamoDBRunbook(a)})}generateRDSRunbook(e,t){return{estimatedDuration:60,requiredApprovals:["cto","engineering-lead"],steps:[{order:1,name:"Verify Primary Database Failure",description:"Confirm that the primary database is truly unavailable and not experiencing temporary issues",action:"aws rds describe-db-instances --region "+e,automatable:!0,estimatedDuration:2,rollbackable:!1},{order:2,name:"Check Replication Lag",description:"Verify that the read replica is up to date",action:"Check ReplicaLag metric in CloudWatch",automatable:!0,estimatedDuration:1,rollbackable:!1},{order:3,name:"Promote Read Replica",description:"Promote the read replica in the secondary region to be the new primary",action:"aws rds promote-read-replica --db-instance-identifier replica --region "+t,automatable:!0,estimatedDuration:10,rollbackable:!1},{order:4,name:"Update DNS Records",description:"Update Route53 records to point to the new primary database",action:"Update Route53 failover record set",automatable:!0,estimatedDuration:5,rollbackable:!0},{order:5,name:"Update Application Configuration",description:"Update application connection strings if needed",action:"Deploy configuration update to ECS/Lambda",automatable:!0,estimatedDuration:10,rollbackable:!0},{order:6,name:"Verify Application Connectivity",description:"Test that applications can connect to the new primary",action:"Run smoke tests",automatable:!0,estimatedDuration:5,rollbackable:!1},{order:7,name:"Monitor for Issues",description:"Monitor CloudWatch metrics and application logs",action:"Monitor for 30 minutes",automatable:!1,estimatedDuration:30,rollbackable:!1}]}}generateDynamoDBRunbook(e){return{estimatedDuration:15,steps:[{order:1,name:"Verify Primary Region Failure",description:"Confirm that the primary region is experiencing an outage",action:"Check AWS Health Dashboard",automatable:!0,estimatedDuration:2,rollbackable:!1},{order:2,name:"Update Route53 Failover",description:"Update Route53 to direct traffic to secondary region",action:"Update Route53 health check and failover records",automatable:!0,estimatedDuration:5,rollbackable:!0},{order:3,name:"Update Application Endpoints",description:"Update Lambda/ECS to use secondary region DynamoDB endpoint",action:"Deploy configuration update",automatable:!0,estimatedDuration:5,rollbackable:!0},{order:4,name:"Verify Data Consistency",description:"Verify that data is consistent in secondary region",action:"Run data validation queries",automatable:!0,estimatedDuration:3,rollbackable:!1}]}}async executeFailover(e,t=!1){let a=this.drPlans.get(e);if(!a)throw Error(`DR plan not found: ${e}`);let r=Date.now(),n=0;console.log(`${t?"[DRY RUN] ":""}Executing failover for plan: ${a.name}`),console.log(`Primary: ${a.primaryRegion} -> Secondary: ${a.secondaryRegion}`),console.log(`RTO: ${a.rto} minutes, RPO: ${a.rpo} minutes`),console.log("");for(let i of a.runbook.steps){if(console.log(`Step ${i.order}: ${i.name}`),console.log(` ${i.description}`),console.log(` Action: ${i.action}`),console.log(` Estimated: ${i.estimatedDuration} minutes`),t)console.log(" [SKIPPED - DRY RUN]");else if(i.automatable)console.log(" [AUTOMATED]");else console.log(" [MANUAL - WAITING]");n++,console.log("")}return{success:!0,duration:(Date.now()-r)/1000/60,completedSteps:n}}scheduleFailoverTest(e,t){let a={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:e,status:"scheduled",startTime:t};return this.failoverTests.set(a.id,a),a}async runFailoverTest(e){let t=this.drPlans.get(e);if(!t)throw Error(`DR plan not found: ${e}`);let a={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:e,status:"running",startTime:new Date,results:[]};this.failoverTests.set(a.id,a),console.log(`Running failover test for plan: ${t.name}`),console.log("This is a non-destructive test using test resources"),console.log("");for(let r of t.runbook.steps){let n=Date.now();console.log(`Testing step ${r.order}: ${r.name}`);let i={step:r.name,status:"success",duration:(Date.now()-n)/1000,message:`Successfully validated step ${r.order}`};a.results.push(i)}return a.status="completed",a.endTime=new Date,a}getDRPlan(e){return this.drPlans.get(e)}listDRPlans(){return Array.from(this.drPlans.values())}getFailoverTest(e){return this.failoverTests.get(e)}listFailoverTests(){return Array.from(this.failoverTests.values())}validateDRPlan(e){let t=[],a=[];if(e.rto<e.rpo)a.push("RTO cannot be less than RPO");if(e.rto>240)t.push("RTO exceeds 4 hours - consider improving recovery time");if(e.rpo>60)t.push("RPO exceeds 1 hour - consider more frequent backups");if(e.resources.length===0)a.push("No resources defined in DR plan");for(let i of e.resources){if(!i.replicationEnabled)t.push(`Resource ${i.resourceId} does not have replication enabled`);if(!i.secondaryArn&&i.resourceType!=="dynamodb")t.push(`Resource ${i.resourceId} does not have secondary resource defined`)}if(e.runbook.steps.length===0)a.push("No recovery steps defined in runbook");let r=e.runbook.steps.reduce((i,s)=>i+s.estimatedDuration,0);if(r>e.rto)t.push(`Estimated recovery duration (${r}m) exceeds RTO (${e.rto}m)`);let n=e.runbook.steps.filter((i)=>!i.automatable);if(n.length>0)t.push(`${n.length} manual steps in runbook - consider automation`);return{valid:a.length===0,warnings:t,errors:a}}clear(){this.drPlans.clear(),this.failoverTests.clear(),this.planCounter=0,this.testCounter=0}}var Yd=new wr;class Er{configRules=new Map;configRecorders=new Map;deliveryChannels=new Map;ruleCounter=0;createConfigRecorder(e){return this.configRecorders.set(e.name,e),e}createDeliveryChannel(e){return this.deliveryChannels.set(e.name,e),e}createConfigRule(e){let t=`config-rule-${Date.now()}-${this.ruleCounter++}`,a={id:t,...e};return this.configRules.set(t,a),a}createS3EncryptionRule(){return this.createConfigRule({name:"s3-bucket-server-side-encryption-enabled",description:"Checks that S3 buckets have server-side encryption enabled",source:"AWS_MANAGED",identifier:"S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED",scope:{complianceResourceTypes:["AWS::S3::Bucket"]}})}createS3PublicAccessBlockRule(){return this.createConfigRule({name:"s3-bucket-public-read-prohibited",description:"Checks that S3 buckets do not allow public read access",source:"AWS_MANAGED",identifier:"S3_BUCKET_PUBLIC_READ_PROHIBITED",scope:{complianceResourceTypes:["AWS::S3::Bucket"]}})}createS3VersioningRule(){return this.createConfigRule({name:"s3-bucket-versioning-enabled",description:"Checks whether versioning is enabled for S3 buckets",source:"AWS_MANAGED",identifier:"S3_BUCKET_VERSIONING_ENABLED",scope:{complianceResourceTypes:["AWS::S3::Bucket"]}})}createRdsEncryptionRule(){return this.createConfigRule({name:"rds-storage-encrypted",description:"Checks whether storage encryption is enabled for RDS DB instances",source:"AWS_MANAGED",identifier:"RDS_STORAGE_ENCRYPTED",scope:{complianceResourceTypes:["AWS::RDS::DBInstance"]}})}createRdsSnapshotEncryptionRule(){return this.createConfigRule({name:"rds-snapshots-public-prohibited",description:"Checks if RDS snapshots are public",source:"AWS_MANAGED",identifier:"RDS_SNAPSHOTS_PUBLIC_PROHIBITED",scope:{complianceResourceTypes:["AWS::RDS::DBSnapshot","AWS::RDS::DBClusterSnapshot"]}})}createRdsBackupRule(e=7){return this.createConfigRule({name:"db-backup-enabled",description:"Checks whether RDS DB instances have backups enabled",source:"AWS_MANAGED",identifier:"DB_BACKUP_ENABLED",inputParameters:{backupRetentionPeriod:e},scope:{complianceResourceTypes:["AWS::RDS::DBInstance"]}})}createEc2InstanceProfileRule(){return this.createConfigRule({name:"ec2-instance-managed-by-systems-manager",description:"Checks if EC2 instances are managed by Systems Manager",source:"AWS_MANAGED",identifier:"EC2_INSTANCE_MANAGED_BY_SSM",scope:{complianceResourceTypes:["AWS::EC2::Instance"]}})}createEbsEncryptionRule(){return this.createConfigRule({name:"encrypted-volumes",description:"Checks whether EBS volumes are encrypted",source:"AWS_MANAGED",identifier:"ENCRYPTED_VOLUMES",scope:{complianceResourceTypes:["AWS::EC2::Volume"]}})}createIamPasswordPolicyRule(){return this.createConfigRule({name:"iam-password-policy",description:"Checks whether the IAM password policy meets specified requirements",source:"AWS_MANAGED",identifier:"IAM_PASSWORD_POLICY",inputParameters:{RequireUppercaseCharacters:!0,RequireLowercaseCharacters:!0,RequireSymbols:!0,RequireNumbers:!0,MinimumPasswordLength:14,PasswordReusePrevention:24,MaxPasswordAge:90}})}createIamMfaRule(){return this.createConfigRule({name:"iam-user-mfa-enabled",description:"Checks whether IAM users have MFA enabled",source:"AWS_MANAGED",identifier:"IAM_USER_MFA_ENABLED"})}createRootAccountMfaRule(){return this.createConfigRule({name:"root-account-mfa-enabled",description:"Checks whether the root account has MFA enabled",source:"AWS_MANAGED",identifier:"ROOT_ACCOUNT_MFA_ENABLED"})}createVpcFlowLogsRule(){return this.createConfigRule({name:"vpc-flow-logs-enabled",description:"Checks whether VPC Flow Logs is enabled",source:"AWS_MANAGED",identifier:"VPC_FLOW_LOGS_ENABLED",scope:{complianceResourceTypes:["AWS::EC2::VPC"]}})}createCloudTrailEnabledRule(){return this.createConfigRule({name:"cloudtrail-enabled",description:"Checks whether CloudTrail is enabled",source:"AWS_MANAGED",identifier:"CLOUD_TRAIL_ENABLED",maxExecutionFrequency:"TwentyFour_Hours"})}createCloudWatchAlarmRule(){return this.createConfigRule({name:"cloudwatch-alarm-action-check",description:"Checks whether CloudWatch alarms have actions configured",source:"AWS_MANAGED",identifier:"CLOUDWATCH_ALARM_ACTION_CHECK",inputParameters:{alarmActionRequired:!0,insufficientDataActionRequired:!1,okActionRequired:!1},scope:{complianceResourceTypes:["AWS::CloudWatch::Alarm"]}})}createCustomLambdaRule(e){return this.createConfigRule({name:e.name,description:e.description,source:"CUSTOM_LAMBDA",lambdaFunctionArn:e.lambdaFunctionArn,scope:e.resourceTypes?{complianceResourceTypes:e.resourceTypes}:void 0,maxExecutionFrequency:e.maxExecutionFrequency,inputParameters:e.inputParameters})}createCompliancePreset(e){let t=[];switch(e){case"hipaa":t.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createRdsBackupRule(7),this.createVpcFlowLogsRule());break;case"pci-dss":t.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createIamMfaRule(),this.createRootAccountMfaRule(),this.createVpcFlowLogsRule());break;case"sox":t.push(this.createS3VersioningRule(),this.createCloudTrailEnabledRule(),this.createRdsBackupRule(30),this.createIamPasswordPolicyRule());break;case"gdpr":t.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createRdsSnapshotEncryptionRule());break;case"basic":t.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamMfaRule(),this.createRootAccountMfaRule());break}return t}getConfigRule(e){return this.configRules.get(e)}listConfigRules(){return Array.from(this.configRules.values())}getConfigRecorder(e){return this.configRecorders.get(e)}listConfigRecorders(){return Array.from(this.configRecorders.values())}getDeliveryChannel(e){return this.deliveryChannels.get(e)}listDeliveryChannels(){return Array.from(this.deliveryChannels.values())}generateConfigRuleCF(e){let t={Type:"AWS::Config::ConfigRule",Properties:{ConfigRuleName:e.name,Description:e.description,Source:{Owner:e.source==="AWS_MANAGED"?"AWS":"CUSTOM_LAMBDA"}}};if(e.source==="AWS_MANAGED"&&e.identifier)t.Properties.Source.SourceIdentifier=e.identifier;if(e.source==="CUSTOM_LAMBDA"&&e.lambdaFunctionArn)t.Properties.Source.SourceIdentifier=e.lambdaFunctionArn,t.Properties.Source.SourceDetails=[{EventSource:"aws.config",MessageType:"ConfigurationItemChangeNotification"}];if(e.inputParameters)t.Properties.InputParameters=JSON.stringify(e.inputParameters);if(e.scope){if(t.Properties.Scope={},e.scope.complianceResourceTypes)t.Properties.Scope.ComplianceResourceTypes=e.scope.complianceResourceTypes;if(e.scope.tagKey)t.Properties.Scope.TagKey=e.scope.tagKey;if(e.scope.tagValue)t.Properties.Scope.TagValue=e.scope.tagValue}if(e.maxExecutionFrequency)t.Properties.MaximumExecutionFrequency=e.maxExecutionFrequency;return t}generateConfigRecorderCF(e){return{Type:"AWS::Config::ConfigurationRecorder",Properties:{Name:e.name,RoleArn:e.roleArn,RecordingGroup:e.recordingGroup||{AllSupported:!0,IncludeGlobalResourceTypes:!0}}}}generateDeliveryChannelCF(e){return{Type:"AWS::Config::DeliveryChannel",Properties:{Name:e.name,S3BucketName:e.s3BucketName,...e.s3KeyPrefix&&{S3KeyPrefix:e.s3KeyPrefix},...e.snsTopicArn&&{SnsTopicARN:e.snsTopicArn},...e.configSnapshotDeliveryProperties&&{ConfigSnapshotDeliveryProperties:e.configSnapshotDeliveryProperties}}}}clear(){this.configRules.clear(),this.configRecorders.clear(),this.deliveryChannels.clear(),this.ruleCounter=0}}var Zd=new Er;class Pr{trails=new Map;trailCounter=0;createTrail(e){let t=`trail-${Date.now()}-${this.trailCounter++}`,a={id:t,...e};return this.trails.set(t,a),a}createOrganizationTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,s3KeyPrefix:"organization-trail",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:e.kmsKeyId,cloudWatchLogsLogGroupArn:e.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:e.cloudWatchLogsRoleArn})}createSecurityAuditTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,s3KeyPrefix:"security-audit",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:e.kmsKeyId,cloudWatchLogsLogGroupArn:e.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:e.cloudWatchLogsRoleArn,eventSelectors:[{readWriteType:"All",includeManagementEvents:!0,excludeManagementEventSources:[]}],insightSelectors:[{insightType:"ApiCallRateInsight"},{insightType:"ApiErrorRateInsight"}]})}createDataEventsTrail(e){let t=[];if(e.s3DataBuckets&&e.s3DataBuckets.length>0)t.push({type:"AWS::S3::Object",values:e.s3DataBuckets.map((a)=>`arn:aws:s3:::${a}/*`)});if(e.lambdaFunctions&&e.lambdaFunctions.length>0)t.push({type:"AWS::Lambda::Function",values:e.lambdaFunctions});return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,s3KeyPrefix:"data-events",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"All",includeManagementEvents:!1,dataResources:t}]})}createAdvancedTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,advancedEventSelectors:e.selectors})}createReadOnlyTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"ReadOnly",includeManagementEvents:!0}]})}createWriteOnlyTrail(e){return this.createTrail({name:e.name,s3BucketName:e.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"WriteOnly",includeManagementEvents:!0}]})}getTrail(e){return this.trails.get(e)}listTrails(){return Array.from(this.trails.values())}generateTrailCF(e){let t={Type:"AWS::CloudTrail::Trail",Properties:{TrailName:e.name,S3BucketName:e.s3BucketName,IsLogging:!0,IncludeGlobalServiceEvents:e.includeGlobalServiceEvents??!0,IsMultiRegionTrail:e.isMultiRegionTrail??!0,EnableLogFileValidation:e.enableLogFileValidation??!0}};if(e.s3KeyPrefix)t.Properties.S3KeyPrefix=e.s3KeyPrefix;if(e.cloudWatchLogsLogGroupArn)t.Properties.CloudWatchLogsLogGroupArn=e.cloudWatchLogsLogGroupArn;if(e.cloudWatchLogsRoleArn)t.Properties.CloudWatchLogsRoleArn=e.cloudWatchLogsRoleArn;if(e.snsTopicName)t.Properties.SnsTopicName=e.snsTopicName;if(e.kmsKeyId)t.Properties.KMSKeyId=e.kmsKeyId;if(e.eventSelectors)t.Properties.EventSelectors=e.eventSelectors.map((a)=>({ReadWriteType:a.readWriteType,IncludeManagementEvents:a.includeManagementEvents??!0,...a.dataResources&&{DataResources:a.dataResources.map((r)=>({Type:r.type,Values:r.values}))},...a.excludeManagementEventSources&&{ExcludeManagementEventSources:a.excludeManagementEventSources}}));if(e.insightSelectors)t.Properties.InsightSelectors=e.insightSelectors.map((a)=>({InsightType:a.insightType}));if(e.advancedEventSelectors)t.Properties.AdvancedEventSelectors=e.advancedEventSelectors.map((a)=>({Name:a.name,FieldSelectors:a.fieldSelectors.map((r)=>({Field:r.field,...r.equals&&{Equals:r.equals},...r.startsWith&&{StartsWith:r.startsWith},...r.endsWith&&{EndsWith:r.endsWith},...r.notEquals&&{NotEquals:r.notEquals},...r.notStartsWith&&{NotStartsWith:r.notStartsWith},...r.notEndsWith&&{NotEndsWith:r.notEndsWith}}))}));return t}generateBucketPolicy(e,t){return{Version:"2012-10-17",Statement:[{Sid:"AWSCloudTrailAclCheck",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:GetBucketAcl",Resource:`arn:aws:s3:::${e}`},{Sid:"AWSCloudTrailWrite",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:PutObject",Resource:t.map((a)=>`arn:aws:s3:::${e}/AWSLogs/${a}/*`),Condition:{StringEquals:{"s3:x-amz-acl":"bucket-owner-full-control"}}}]}}clear(){this.trails.clear(),this.trailCounter=0}}var Xd=new Pr;class Ir{detectors=new Map;threatIntelSets=new Map;ipSets=new Map;filters=new Map;detectorCounter=0;threatIntelCounter=0;ipSetCounter=0;filterCounter=0;createDetector(e){let t=`detector-${Date.now()}-${this.detectorCounter++}`,a={id:t,...e};return this.detectors.set(t,a),a}createComprehensiveDetector(){return this.createDetector({enable:!0,findingPublishingFrequency:"FIFTEEN_MINUTES",dataSources:{s3Logs:{enable:!0},kubernetes:{auditLogs:{enable:!0}},malwareProtection:{scanEc2InstanceWithFindings:{ebsVolumes:{enable:!0}}}},features:[{name:"S3_DATA_EVENTS",status:"ENABLED"},{name:"EKS_AUDIT_LOGS",status:"ENABLED"},{name:"EBS_MALWARE_PROTECTION",status:"ENABLED"},{name:"RDS_LOGIN_EVENTS",status:"ENABLED"},{name:"LAMBDA_NETWORK_LOGS",status:"ENABLED"}]})}createBasicDetector(){return this.createDetector({enable:!0,findingPublishingFrequency:"SIX_HOURS"})}createThreatIntelSet(e){let t=`threat-intel-${Date.now()}-${this.threatIntelCounter++}`,a={id:t,...e};return this.threatIntelSets.set(t,a),a}createIPSet(e){let t=`ip-set-${Date.now()}-${this.ipSetCounter++}`,a={id:t,...e};return this.ipSets.set(t,a),a}createFindingFilter(e){let t=`filter-${Date.now()}-${this.filterCounter++}`,a={id:t,...e};return this.filters.set(t,a),a}createLowSeverityArchiveFilter(e){return this.createFindingFilter({detectorId:e,name:"archive-low-severity",description:"Automatically archive low severity findings",action:"ARCHIVE",rank:1,findingCriteria:{criterion:{severity:{lt:4}}}})}createFindingTypeFilter(e,t,a){return this.createFindingFilter({detectorId:e,name:`filter-finding-types-${a.toLowerCase()}`,description:`${a==="ARCHIVE"?"Archive":"Keep"} specific finding types`,action:a,rank:2,findingCriteria:{criterion:{type:{eq:t}}}})}createTrustedIPFilter(e,t){return this.createFindingFilter({detectorId:e,name:"trusted-ip-addresses",description:"Archive findings from trusted IP addresses",action:"ARCHIVE",rank:3,findingCriteria:{criterion:{"resource.instanceDetails.networkInterfaces.privateIpAddress":{eq:t}}}})}getDetector(e){return this.detectors.get(e)}listDetectors(){return Array.from(this.detectors.values())}getThreatIntelSet(e){return this.threatIntelSets.get(e)}listThreatIntelSets(){return Array.from(this.threatIntelSets.values())}getIPSet(e){return this.ipSets.get(e)}listIPSets(){return Array.from(this.ipSets.values())}getFindingFilter(e){return this.filters.get(e)}listFindingFilters(){return Array.from(this.filters.values())}generateDetectorCF(e){let t={Type:"AWS::GuardDuty::Detector",Properties:{Enable:e.enable}};if(e.findingPublishingFrequency)t.Properties.FindingPublishingFrequency=e.findingPublishingFrequency;if(e.dataSources){if(t.Properties.DataSources={},e.dataSources.s3Logs)t.Properties.DataSources.S3Logs={Enable:e.dataSources.s3Logs.enable};if(e.dataSources.kubernetes)t.Properties.DataSources.Kubernetes={AuditLogs:{Enable:e.dataSources.kubernetes.auditLogs.enable}};if(e.dataSources.malwareProtection)t.Properties.DataSources.MalwareProtection={ScanEc2InstanceWithFindings:{EbsVolumes:{Enable:e.dataSources.malwareProtection.scanEc2InstanceWithFindings.ebsVolumes.enable}}}}if(e.features)t.Properties.Features=e.features.map((a)=>({Name:a.name,Status:a.status,...a.additionalConfiguration&&{AdditionalConfiguration:a.additionalConfiguration}}));return t}generateThreatIntelSetCF(e){return{Type:"AWS::GuardDuty::ThreatIntelSet",Properties:{DetectorId:e.detectorId,Name:e.name,Format:e.format,Location:e.location,Activate:e.activate}}}generateIPSetCF(e){return{Type:"AWS::GuardDuty::IPSet",Properties:{DetectorId:e.detectorId,Name:e.name,Format:e.format,Location:e.location,Activate:e.activate}}}generateFilterCF(e){return{Type:"AWS::GuardDuty::Filter",Properties:{DetectorId:e.detectorId,Name:e.name,Description:e.description,Action:e.action,Rank:e.rank,FindingCriteria:{Criterion:e.findingCriteria.criterion}}}}clear(){this.detectors.clear(),this.threatIntelSets.clear(),this.ipSets.clear(),this.filters.clear(),this.detectorCounter=0,this.threatIntelCounter=0,this.ipSetCounter=0,this.filterCounter=0}}var em=new Ir;class xe{hubs=new Map;hubCounter=0;ruleCounter=0;static Standards={AWS_FOUNDATIONAL_SECURITY:{arn:"arn:aws:securityhub:::ruleset/aws-foundational-security-best-practices/v/1.0.0",name:"AWS Foundational Security Best Practices",description:"AWS recommended security best practices"},CIS_AWS_FOUNDATIONS_1_2:{arn:"arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0",name:"CIS AWS Foundations Benchmark v1.2.0",description:"CIS AWS Foundations Benchmark v1.2.0"},CIS_AWS_FOUNDATIONS_1_4:{arn:"arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.4.0",name:"CIS AWS Foundations Benchmark v1.4.0",description:"CIS AWS Foundations Benchmark v1.4.0"},PCI_DSS:{arn:"arn:aws:securityhub:us-east-1::standards/pci-dss/v/3.2.1",name:"PCI DSS v3.2.1",description:"Payment Card Industry Data Security Standard"},NIST_800_53:{arn:"arn:aws:securityhub:us-east-1::standards/nist-800-53/v/5.0.0",name:"NIST SP 800-53 Rev. 5",description:"NIST Special Publication 800-53 Revision 5"}};createHub(e){let t=`hub-${Date.now()}-${this.hubCounter++}`,a={id:t,...e};return this.hubs.set(t,a),a}createComprehensiveHub(){return this.createHub({enable:!0,controlFindingGenerator:"SECURITY_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...xe.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...xe.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...xe.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...xe.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0}]})}createLowSeveritySuppressionRule(){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:"Suppress Low Severity Informational Findings",description:"Automatically suppress informational findings",actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"SUPPRESSED"},note:{text:"Automatically suppressed low severity finding",updatedBy:"SecurityHub Automation"}}}],criteria:{severityLabel:[{value:"INFORMATIONAL",comparison:"EQUALS"}],recordState:[{value:"ACTIVE",comparison:"EQUALS"}]},ruleStatus:"ENABLED",ruleOrder:1}}createResourceTypeNotificationRule(e){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:"Notify on Critical Resource Findings",description:"Set findings for critical resources to NOTIFIED status",actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"NOTIFIED"},note:{text:"Critical resource finding requires attention",updatedBy:"SecurityHub Automation"}}}],criteria:{resourceType:e.map((t)=>({value:t,comparison:"EQUALS"})),severityLabel:[{value:"HIGH",comparison:"EQUALS"},{value:"CRITICAL",comparison:"EQUALS"}],workflowStatus:[{value:"NEW",comparison:"EQUALS"}]},ruleStatus:"ENABLED",ruleOrder:2}}createComplianceFailureRule(){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:"Flag Compliance Failures",description:"Increase severity for compliance failures",actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{severity:{label:"HIGH"},workflow:{status:"NOTIFIED"},note:{text:"Compliance failure detected - requires immediate attention",updatedBy:"SecurityHub Automation"}}}],criteria:{complianceStatus:[{value:"FAILED",comparison:"EQUALS"}],recordState:[{value:"ACTIVE",comparison:"EQUALS"}]},ruleStatus:"ENABLED",ruleOrder:3}}createFalsePositiveSuppressionRule(e,t){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:`Suppress False Positives - ${e}`,description:`Automatically suppress known false positives from ${e}`,actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"SUPPRESSED"},note:{text:"Known false positive - automatically suppressed",updatedBy:"SecurityHub Automation"}}}],criteria:{productName:[{value:e,comparison:"EQUALS"}],title:t.map((a)=>({value:a,comparison:"PREFIX"}))},ruleStatus:"ENABLED",ruleOrder:10}}getHub(e){return this.hubs.get(e)}listHubs(){return Array.from(this.hubs.values())}generateHubCF(e){let t={Type:"AWS::SecurityHub::Hub",Properties:{}};if(e.controlFindingGenerator)t.Properties.ControlFindingGenerator=e.controlFindingGenerator;if(e.enableDefaultStandards!==void 0)t.Properties.EnableDefaultStandards=e.enableDefaultStandards;return t}generateStandardCF(e){let t={Type:"AWS::SecurityHub::Standard",Properties:{StandardsArn:e.arn}};if(e.disabledControls&&e.disabledControls.length>0)t.Properties.DisabledStandardsControls=e.disabledControls.map((a)=>({StandardsControlArn:a,Reason:"Disabled by configuration"}));return t}generateAutomationRuleCF(e){return{Type:"AWS::SecurityHub::AutomationRule",Properties:{RuleName:e.ruleName,Description:e.description,Actions:e.actions.map((t)=>({Type:t.type,FindingFieldsUpdate:t.findingFieldsUpdate})),Criteria:e.criteria,RuleStatus:e.ruleStatus,RuleOrder:e.ruleOrder}}}clear(){this.hubs.clear(),this.hubCounter=0,this.ruleCounter=0}}var tm=new xe;class Rr{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;createDeployment(e){let t=`bg-deployment-${Date.now()}-${this.deploymentCounter++}`,a={id:t,...e};return this.deployments.set(t,a),a}createALBDeployment(e){return this.createDeployment({name:e.name,blueEnvironment:{name:"blue",targetGroupArn:e.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:e.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:e.listenerArn,switchoverTimeSeconds:0},autoPromote:e.autoPromote,healthCheckConfig:e.healthCheckConfig})}createRoute53Deployment(e){return this.createDeployment({name:e.name,blueEnvironment:{name:"blue",targetGroupArn:e.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:e.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"route53",hostedZoneId:e.hostedZoneId,switchoverTimeSeconds:e.switchoverTimeSeconds||60}})}createECSDeployment(e){return this.createDeployment({name:e.name,blueEnvironment:{name:"blue",targetGroupArn:e.blueTargetGroupArn,taskDefinitionArn:e.blueTaskDefinitionArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:e.greenTargetGroupArn,taskDefinitionArn:e.greenTaskDefinitionArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:e.listenerArn},autoRollback:e.autoRollback??!0})}async executeDeployment(e,t=!1){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);let r={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!1,errors:[]};console.log(`${t?"[DRY RUN] ":""}Starting blue/green deployment: ${a.name}`),console.log(` Active environment: ${a.activeEnvironment}`),console.log(` Routing type: ${a.routingConfig.type}`);let n=a.activeEnvironment==="blue"?"green":"blue";if(console.log(` Switching to: ${n}`),console.log(`\\n1. Deploying to ${n} environment`),!t)await new Promise((i)=>setTimeout(i,100));if(console.log(`\\n2. Running health checks on ${n} environment`),a.healthCheckConfig){let i=await this.runHealthChecks(a,n,t);if(r.healthChecksPassed=i,!i){if(r.errors?.push("Health checks failed"),r.endTime=new Date,a.autoRollback)console.log(" Auto-rollback enabled - keeping current environment active"),r.rolledBackAt=new Date;return this.recordDeployment(e,r),r}}else r.healthChecksPassed=!0;if(console.log(`\\n3. Switching traffic to ${n} environment`),!t)a.activeEnvironment=n,r.switchedAt=new Date;if(console.log(`\\n4. Monitoring ${n} environment`),!t)await new Promise((i)=>setTimeout(i,100));return r.success=!0,r.endTime=new Date,console.log("\\n✓ Deployment completed successfully"),this.recordDeployment(e,r),r}async rollback(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);let a={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!0,errors:[]};console.log(`Rolling back deployment: ${t.name}`);let r=t.activeEnvironment==="blue"?"green":"blue";return t.activeEnvironment=r,a.success=!0,a.rolledBackAt=new Date,a.endTime=new Date,console.log(` Switched back to: ${r}`),this.recordDeployment(e,a),a}async runHealthChecks(e,t,a){let r=e.healthCheckConfig;if(console.log(` Health check path: ${r.path||"/"}`),console.log(` Healthy threshold: ${r.healthyThreshold}`),console.log(` Interval: ${r.interval}s`),a)return console.log(" [SKIPPED - DRY RUN]"),!0;let n=0,i=r.healthyThreshold+2;for(let s=0;s<i;s++)if(await new Promise((o)=>setTimeout(o,50)),Math.random()>0.1){if(n++,console.log(` Check ${s+1}: ✓ Healthy (${n}/${r.healthyThreshold})`),n>=r.healthyThreshold)return!0}else n=0,console.log(` Check ${s+1}: ✗ Unhealthy`);return!1}recordDeployment(e,t){if(!this.deploymentHistory.has(e))this.deploymentHistory.set(e,[]);this.deploymentHistory.get(e).push(t)}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(e){return this.deploymentHistory.get(e)||[]}generateALBListenerCF(e){let t=e.activeEnvironment==="blue"?e.blueEnvironment:e.greenEnvironment;return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:e.routingConfig.listenerArn,Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",TargetGroupArn:t.targetGroupArn}]}}}generateRoute53RecordSetCF(e,t){return[{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.routingConfig.hostedZoneId,Name:t,Type:"A",SetIdentifier:"blue",Weight:e.activeEnvironment==="blue"?100:0,AliasTarget:{HostedZoneId:e.routingConfig.hostedZoneId,DNSName:e.blueEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}},{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.routingConfig.hostedZoneId,Name:t,Type:"A",SetIdentifier:"green",Weight:e.activeEnvironment==="green"?100:0,AliasTarget:{HostedZoneId:e.routingConfig.hostedZoneId,DNSName:e.greenEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}}]}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var am=new Rr;class Ct{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;static Strategies={CONSERVATIVE:[{name:"Initial Canary",trafficPercentage:10,durationMinutes:10},{name:"Quarter Traffic",trafficPercentage:25,durationMinutes:10},{name:"Half Traffic",trafficPercentage:50,durationMinutes:15},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}],BALANCED:[{name:"Initial Canary",trafficPercentage:20,durationMinutes:5},{name:"Half Traffic",trafficPercentage:50,durationMinutes:10},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}],AGGRESSIVE:[{name:"Half Traffic",trafficPercentage:50,durationMinutes:5},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}],LINEAR_10:[{name:"Canary 10%",trafficPercentage:10,durationMinutes:5},{name:"Canary 20%",trafficPercentage:20,durationMinutes:5},{name:"Canary 30%",trafficPercentage:30,durationMinutes:5},{name:"Canary 40%",trafficPercentage:40,durationMinutes:5},{name:"Canary 50%",trafficPercentage:50,durationMinutes:5},{name:"Canary 60%",trafficPercentage:60,durationMinutes:5},{name:"Canary 70%",trafficPercentage:70,durationMinutes:5},{name:"Canary 80%",trafficPercentage:80,durationMinutes:5},{name:"Canary 90%",trafficPercentage:90,durationMinutes:5},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}]};createDeployment(e){let t=`canary-${Date.now()}-${this.deploymentCounter++}`,a={id:t,...e};return this.deployments.set(t,a),a}createLambdaCanaryDeployment(e){let t=e.strategy||"BALANCED",a=Ct.Strategies[t].map((r)=>({...r,alarmThresholds:{errorRate:e.errorRateThreshold||1,latencyP99:e.latencyThreshold||1000}}));return this.createDeployment({name:e.name,baselineVersion:{version:"baseline",functionVersionArn:e.baselineVersionArn,weight:100},canaryVersion:{version:"canary",functionVersionArn:e.canaryVersionArn,weight:0},stages:a,currentStage:0,status:"pending",autoPromote:e.autoPromote??!0,autoRollback:!0})}createECSCanaryDeployment(e){let t=e.strategy||"CONSERVATIVE",a=Ct.Strategies[t];return this.createDeployment({name:e.name,baselineVersion:{version:"baseline",taskDefinitionArn:e.baselineTaskDefinitionArn,targetGroupArn:e.baselineTargetGroupArn,weight:100},canaryVersion:{version:"canary",taskDefinitionArn:e.canaryTaskDefinitionArn,targetGroupArn:e.canaryTargetGroupArn,weight:0},stages:a,currentStage:0,status:"pending",autoRollback:!0})}async executeDeployment(e,t=!1){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);let r={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,completedStages:0,rolledBack:!1};console.log(`${t?"[DRY RUN] ":""}Starting canary deployment: ${a.name}`),console.log(` Strategy: ${a.stages.length} stages`),console.log(` Auto-promote: ${a.autoPromote}`),console.log(` Auto-rollback: ${a.autoRollback}`),console.log(""),a.status="in_progress";for(let n=0;n<a.stages.length;n++){let i=a.stages[n];if(a.currentStage=n,console.log(`Stage ${n+1}/${a.stages.length}: ${i.name}`),console.log(` Traffic: ${i.trafficPercentage}% canary, ${100-i.trafficPercentage}% baseline`),console.log(` Duration: ${i.durationMinutes} minutes`),!t)a.baselineVersion.weight=100-i.trafficPercentage,a.canaryVersion.weight=i.trafficPercentage;if(!await this.monitorStage(a,i,t)){if(console.log(" ✗ Stage failed - metrics exceeded thresholds"),a.autoRollback)console.log("\\n Rolling back deployment..."),await this.rollback(e,t),r.rolledBack=!0,r.reason="Metrics exceeded thresholds";return r.endTime=new Date,a.status="rolled_back",this.recordDeployment(e,r),r}console.log(" ✓ Stage completed successfully"),r.completedStages++,console.log("")}return a.status="completed",r.success=!0,r.endTime=new Date,console.log("✓ Canary deployment completed successfully"),this.recordDeployment(e,r),r}async monitorStage(e,t,a){if(console.log(" Monitoring metrics..."),a)return console.log(" [SKIPPED - DRY RUN]"),!0;await new Promise((n)=>setTimeout(n,100));let r={baselineErrorRate:Math.random()*0.5,canaryErrorRate:Math.random()*0.8,baselineLatencyP99:200+Math.random()*100,canaryLatencyP99:180+Math.random()*150,baselineRequestCount:Math.floor(Math.random()*1000)+500,canaryRequestCount:Math.floor((Math.random()*1000+500)*t.trafficPercentage/100)};if(e.metrics=r,console.log(` Baseline: ${r.baselineErrorRate.toFixed(2)}% errors, ${r.baselineLatencyP99.toFixed(0)}ms P99`),console.log(` Canary: ${r.canaryErrorRate.toFixed(2)}% errors, ${r.canaryLatencyP99.toFixed(0)}ms P99`),t.alarmThresholds){let{errorRate:n,latencyP99:i}=t.alarmThresholds;if(n&&r.canaryErrorRate>n)return console.log(` ⚠ Error rate exceeded threshold: ${r.canaryErrorRate.toFixed(2)}% > ${n}%`),!1;if(i&&r.canaryLatencyP99>i)return console.log(` ⚠ Latency P99 exceeded threshold: ${r.canaryLatencyP99.toFixed(0)}ms > ${i}ms`),!1}return!0}async rollback(e,t=!1){let a=this.deployments.get(e);if(!a)throw Error(`Deployment not found: ${e}`);if(console.log(`${t?"[DRY RUN] ":""}Rolling back canary deployment: ${a.name}`),!t)a.baselineVersion.weight=100,a.canaryVersion.weight=0,a.status="rolled_back";console.log(" Traffic restored to baseline: 100%")}promoteCanary(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);console.log(`Promoting canary to baseline: ${t.name}`);let a=t.baselineVersion;t.baselineVersion=t.canaryVersion,t.canaryVersion=a,t.baselineVersion.weight=100,t.canaryVersion.weight=0,t.status="completed",console.log(" Canary promoted successfully")}recordDeployment(e,t){if(!this.deploymentHistory.has(e))this.deploymentHistory.set(e,[]);this.deploymentHistory.get(e).push(t)}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(e){return this.deploymentHistory.get(e)||[]}generateLambdaAliasCF(e,t){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:{Ref:"LambdaFunction"},Name:t,FunctionVersion:e.canaryVersion.version,RoutingConfig:{AdditionalVersionWeights:[{FunctionVersion:e.baselineVersion.version,FunctionWeight:e.baselineVersion.weight/100}]}}}}generateALBListenerRuleCF(e){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:[{TargetGroupArn:e.baselineVersion.targetGroupArn,Weight:e.baselineVersion.weight},{TargetGroupArn:e.canaryVersion.targetGroupArn,Weight:e.canaryVersion.weight}],TargetGroupStickinessConfig:{Enabled:!1}}}]}}}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var rm=new Ct;class Nr{tests=new Map;testCounter=0;createTest(e){let t=`abtest-${Date.now()}-${this.testCounter++}`,a={id:t,...e};return this.tests.set(t,a),a}createSimpleABTest(e){let t=e.variantTrafficPercentage||50;return this.createTest({name:e.name,description:e.description,variants:[{id:"control",name:"Control",description:"Original version",trafficPercentage:100-t,targetGroupArn:e.controlTargetGroupArn,weight:100-t},{id:"variant-a",name:"Variant A",description:"Test version",trafficPercentage:t,targetGroupArn:e.variantTargetGroupArn,weight:t}],routingStrategy:{type:e.stickySession?"cookie":"random",cookieName:e.stickySession?"ab_variant":void 0,stickySession:e.stickySession??!1,sessionDuration:1440},startTime:new Date,status:"draft"})}createMultivariateTest(e){let t=e.variants.reduce((a,r)=>a+r.trafficPercentage,0);if(t!==100)throw Error(`Traffic percentages must sum to 100, got ${t}`);return this.createTest({name:e.name,description:e.description,variants:e.variants.map((a,r)=>({id:`variant-${r}`,name:a.name,description:a.description,trafficPercentage:a.trafficPercentage,targetGroupArn:a.targetGroupArn,weight:a.trafficPercentage})),routingStrategy:e.routingStrategy||{type:"random",stickySession:!1},startTime:new Date,status:"draft"})}createHeaderBasedTest(e){return this.createTest({name:e.name,description:`Route based on ${e.headerName} header`,variants:[{id:"control",name:"Control",trafficPercentage:50,targetGroupArn:e.controlTargetGroupArn,weight:50},{id:"variant-a",name:"Variant A",trafficPercentage:50,targetGroupArn:e.variantTargetGroupArn,weight:50}],routingStrategy:{type:"header",headerName:e.headerName,stickySession:!1},startTime:new Date,status:"draft"})}createGeoBasedTest(e){return this.createTest({name:e.name,description:"Route based on geographic location",variants:[{id:"control",name:"Control (Rest of World)",trafficPercentage:50,targetGroupArn:e.controlTargetGroupArn,weight:50},{id:"variant-a",name:`Variant A (${e.regions.join(", ")})`,trafficPercentage:50,targetGroupArn:e.variantTargetGroupArn,weight:50}],routingStrategy:{type:"geo",stickySession:!0,sessionDuration:1440},startTime:new Date,status:"draft"})}startTest(e){let t=this.tests.get(e);if(!t)throw Error(`Test not found: ${e}`);if(t.status!=="draft"&&t.status!=="paused")throw Error(`Cannot start test in ${t.status} status`);t.status="active",t.startTime=new Date,console.log(`Started A/B test: ${t.name}`),console.log(` Variants: ${t.variants.length}`),t.variants.forEach((a)=>{console.log(` - ${a.name}: ${a.trafficPercentage}%`)})}pauseTest(e){let t=this.tests.get(e);if(!t)throw Error(`Test not found: ${e}`);t.status="paused",console.log(`Paused A/B test: ${t.name}`)}updateTrafficSplit(e,t,a){let r=this.tests.get(e);if(!r)throw Error(`Test not found: ${e}`);let n=r.variants.find((s)=>s.id===t);if(!n)throw Error(`Variant not found: ${t}`);let i=n.trafficPercentage;n.trafficPercentage=a,n.weight=a,console.log(`Updated ${n.name} traffic: ${i}% → ${a}%`)}analyzeResults(e){let t=this.tests.get(e);if(!t)throw Error(`Test not found: ${e}`);if(!t.metrics)t.metrics=this.collectMetrics(t);let a=t.variants[0],r=0;for(let l of t.variants){let u=t.metrics.variants[l.id];if(u&&u.conversionRate>r)r=u.conversionRate,a=l}let n=t.metrics.variants.control||t.metrics.variants[t.variants[0].id],i=t.metrics.variants[a.id],s=(i.conversionRate-n.conversionRate)/n.conversionRate*100,o=100,c=i.requests>o&&n.requests>o&&Math.abs(s)>10;return{testId:e,winningVariant:a.name,confidence:c?95:75,improvement:s,statisticalSignificance:c,metrics:t.metrics,recommendation:this.generateRecommendation(s,c,a.name)}}declareWinner(e,t){let a=this.tests.get(e);if(!a)throw Error(`Test not found: ${e}`);let r=a.variants.find((n)=>n.id===t);if(!r)throw Error(`Variant not found: ${t}`);a.variants.forEach((n)=>{if(n.id===t)n.trafficPercentage=100,n.weight=100;else n.trafficPercentage=0,n.weight=0}),a.status="completed",a.endTime=new Date,a.winner=t,console.log(`Declared winner: ${r.name}`),console.log(` All traffic now routed to ${r.name}`)}collectMetrics(e){let t={},a=0;for(let r of e.variants){let n=Math.floor(Math.random()*1000)+500,i=Math.floor(n*(Math.random()*0.1+0.05)),s=i/n*100;t[r.id]={requests:n,conversions:i,conversionRate:s,averageLatency:150+Math.random()*100,errorRate:Math.random()*0.5,revenue:i*(Math.random()*50+100)},a+=n}return{variants:t,totalRequests:a,startTime:e.startTime,lastUpdated:new Date}}generateRecommendation(e,t,a){if(!t)return"Continue test - sample size too small or no significant difference detected";if(e>20)return`Strong winner detected - ${a} shows ${e.toFixed(1)}% improvement. Recommend deploying to all traffic.`;if(e>10)return`Moderate improvement - ${a} shows ${e.toFixed(1)}% improvement. Consider deploying.`;if(e>0)return`Minor improvement - ${a} shows ${e.toFixed(1)}% improvement. May not be worth the complexity.`;return"No improvement detected - consider reverting to control variant"}getTest(e){return this.tests.get(e)}listTests(){return Array.from(this.tests.values())}generateALBListenerRuleCF(e){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:e.variants.map((t)=>({TargetGroupArn:t.targetGroupArn,Weight:t.weight})),TargetGroupStickinessConfig:{Enabled:e.routingStrategy.stickySession||!1,DurationSeconds:e.routingStrategy.sessionDuration?e.routingStrategy.sessionDuration*60:void 0}}}]}}}generateLambdaEdgeFunction(e){return`'use strict';
|
|
3601
3601
|
|
|
3602
3602
|
exports.handler = (event, _context, _callback) => {
|
|
3603
3603
|
const request = event.Records[0].cf.request;
|
|
@@ -3621,9 +3621,9 @@ exports.handler = (event, _context, _callback) => {
|
|
|
3621
3621
|
const random = Math.random() * 100;
|
|
3622
3622
|
const _cumulative = 0;
|
|
3623
3623
|
|
|
3624
|
-
${e.variants.map((t,a)
|
|
3624
|
+
${e.variants.map((t,a)=>`if (random < ${t.trafficPercentage+(a>0?e.variants.slice(0,a).reduce((r,n)=>r+n.trafficPercentage,0):0)}) {
|
|
3625
3625
|
variant = '${t.id}';
|
|
3626
|
-
}`
|
|
3626
|
+
}`).join(" else ")}
|
|
3627
3627
|
}
|
|
3628
3628
|
|
|
3629
3629
|
// Set variant cookie
|
|
@@ -3644,7 +3644,7 @@ exports.handler = (event, _context, _callback) => {
|
|
|
3644
3644
|
}`).join(" else ")}
|
|
3645
3645
|
|
|
3646
3646
|
callback(null, request);
|
|
3647
|
-
};`}clear(){this.tests.clear(),this.testCounter=0}}var rm=new Rr;class Nr{rollouts=new Map;flags=new Map;gates=new Map;counter=0;createProgressiveRollout(e,t){let a=`rollout-${Date.now()}-${this.counter++}`,r={id:a,name:e,stages:t,currentStage:0};return this.rollouts.set(a,r),r}createFeatureFlag(e,t=0){let a=`flag-${Date.now()}-${this.counter++}`,r={id:a,name:e,enabled:!1,rolloutPercentage:t,targetingRules:[]};return this.flags.set(a,r),r}createDeploymentGate(e,t,a,r){let n=`gate-${Date.now()}-${this.counter++}`,i={id:n,name:e,type:t,approvers:a,conditions:r};return this.gates.set(n,i),i}clear(){this.rollouts.clear(),this.flags.clear(),this.gates.clear()}}var nm=new Nr;class Dr{configs=new Map;samplingRules=new Map;configCounter=0;ruleCounter=0;createConfig(e){let t=`xray-config-${Date.now()}-${this.configCounter++}`,a={id:t,...e};return this.configs.set(t,a),a}createLambdaConfig(e){return this.createConfig({name:`${e.functionName}-xray`,serviceName:e.functionName,samplingRate:e.samplingRate||0.1,enableActiveTracing:!0})}createECSConfig(e){return this.createConfig({name:`${e.serviceName}-xray`,serviceName:`${e.clusterName}/${e.serviceName}`,samplingRate:e.samplingRate||0.05,enableActiveTracing:!0})}createAPIGatewayConfig(e){return this.createConfig({name:`${e.apiName}-${e.stage}-xray`,serviceName:`${e.apiName}/${e.stage}`,samplingRate:e.samplingRate||0.05,enableActiveTracing:!0})}createSamplingRule(e){let t=`sampling-rule-${Date.now()}-${this.ruleCounter++}`,a={id:t,...e};return this.samplingRules.set(t,a),a}createHighPrioritySamplingRule(e){return this.createSamplingRule({ruleName:e.ruleName,priority:100,fixedRate:1,reservoirSize:100,serviceName:e.serviceName,serviceType:"*",host:"*",httpMethod:"*",urlPath:e.urlPath,version:1})}createErrorSamplingRule(e){return this.createSamplingRule({ruleName:`${e}-errors`,priority:200,fixedRate:1,reservoirSize:50,serviceName:e,serviceType:"*",host:"*",httpMethod:"*",urlPath:"/error/*",version:1})}createDefaultSamplingRule(e,t=0.05){return this.createSamplingRule({ruleName:`${e}-default`,priority:1000,fixedRate:t,reservoirSize:10,serviceName:e,serviceType:"*",host:"*",httpMethod:"*",urlPath:"*",version:1})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getSamplingRule(e){return this.samplingRules.get(e)}listSamplingRules(){return Array.from(this.samplingRules.values())}generateLambdaXRayCF(e){return{TracingConfig:{Mode:e.enableActiveTracing?"Active":"PassThrough"}}}generateAPIGatewayXRayCF(e){return{TracingEnabled:e.enableActiveTracing}}generateECSXRaySidecarCF(){return{Name:"xray-daemon",Image:"public.ecr.aws/xray/aws-xray-daemon:latest",Cpu:32,MemoryReservation:256,PortMappings:[{ContainerPort:2000,Protocol:"udp"}]}}generateSamplingRuleCF(e){return{Type:"AWS::XRay::SamplingRule",Properties:{SamplingRule:{RuleName:e.ruleName,Priority:e.priority,FixedRate:e.fixedRate,ReservoirSize:e.reservoirSize,ServiceName:e.serviceName,ServiceType:e.serviceType,Host:e.host,HTTPMethod:e.httpMethod,URLPath:e.urlPath,Version:e.version,ResourceARN:"*"}}}}createTrace(e,t){return{id:`trace-${Date.now()}-${this.configCounter++}`,traceId:e,spans:t}}clear(){this.configs.clear(),this.samplingRules.clear(),this.configCounter=0,this.ruleCounter=0}}var im=new Dr;class kr{namespaces=new Map;metrics=new Map;namespaceCounter=0;metricCounter=0;alarmCounter=0;createNamespace(e){let t=`namespace-${Date.now()}-${this.namespaceCounter++}`,a={id:t,...e};return this.namespaces.set(t,a),a}createMetric(e){let t=`metric-${Date.now()}-${this.metricCounter++}`,a={id:t,...e};return this.metrics.set(t,a),a}createBusinessMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:e.unit,dimensions:[{name:"Environment",value:"production"},{name:"Type",value:"Business"}]})}createApplicationMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:e.unit,dimensions:[{name:"Service",value:e.serviceName},{name:"Type",value:"Application"}]})}createPerformanceMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:"Milliseconds",dimensions:[{name:"Operation",value:e.operation},{name:"Type",value:"Performance"}]})}createErrorMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:"Count",dimensions:[{name:"ErrorType",value:e.errorType},{name:"Type",value:"Error"}]})}createAlarm(e,t){let a=this.metrics.get(e);if(!a)throw Error(`Metric not found: ${e}`);let r={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...t};if(!a.alarms)a.alarms=[];return a.alarms.push(r),r}createErrorRateAlarm(e){return this.createAlarm(e.metricId,{name:e.name,description:`Alert when error rate exceeds ${e.threshold} errors/min`,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:2,threshold:e.threshold,period:60,statistic:"Sum",treatMissingData:"notBreaching",actionsEnabled:!0,alarmActions:e.snsTopicArn?[e.snsTopicArn]:void 0})}createLatencyAlarm(e){return this.createAlarm(e.metricId,{name:e.name,description:`Alert when latency exceeds ${e.thresholdMs}ms`,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,threshold:e.thresholdMs,period:300,statistic:"Average",treatMissingData:"notBreaching",actionsEnabled:!0,alarmActions:e.snsTopicArn?[e.snsTopicArn]:void 0})}createThroughputAlarm(e){return this.createAlarm(e.metricId,{name:e.name,description:`Alert when throughput drops below ${e.minimumThreshold}`,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,threshold:e.minimumThreshold,period:300,statistic:"Sum",treatMissingData:"breaching",actionsEnabled:!0,alarmActions:e.snsTopicArn?[e.snsTopicArn]:void 0})}createCompositeAlarm(e){return{name:e.name,description:e.description,alarmRule:e.alarmRule,actionsEnabled:e.actionsEnabled??!0,alarmActions:e.alarmActions}}getNamespace(e){return this.namespaces.get(e)}listNamespaces(){return Array.from(this.namespaces.values())}getMetric(e){return this.metrics.get(e)}listMetrics(){return Array.from(this.metrics.values())}generateAlarmCF(e,t){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:t.name,AlarmDescription:t.description,ComparisonOperator:t.comparisonOperator,EvaluationPeriods:t.evaluationPeriods,MetricName:e.name,Namespace:e.namespace,Period:t.period,Statistic:t.statistic,Threshold:t.threshold,TreatMissingData:t.treatMissingData||"notBreaching",ActionsEnabled:t.actionsEnabled??!0,...t.alarmActions&&{AlarmActions:t.alarmActions},...t.okActions&&{OKActions:t.okActions},...t.insufficientDataActions&&{InsufficientDataActions:t.insufficientDataActions},...e.dimensions&&{Dimensions:e.dimensions.map((a)=>({Name:a.name,Value:a.value}))}}}}generateCompositeAlarmCF(e){return{Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:e.name,AlarmDescription:e.description,AlarmRule:e.alarmRule,ActionsEnabled:e.actionsEnabled,...e.alarmActions&&{AlarmActions:e.alarmActions}}}}generateDashboardWidget(e){return{type:"metric",properties:{metrics:[[e.namespace,e.name,...e.dimensions?.flatMap((t)=>[t.name,t.value])||[]]],period:300,stat:"Average",region:"us-east-1",title:e.name}}}publishCustomMetric(e,t,a,r={},n="Count"){return{id:`metric-${Date.now()}-${this.metricCounter++}`,namespace:e,name:t,dimensions:r,value:a,unit:n,timestamp:new Date}}clear(){this.namespaces.clear(),this.metrics.clear(),this.namespaceCounter=0,this.metricCounter=0,this.alarmCounter=0}}var sm=new kr;class Mr{logGroups=new Map;queries=new Map;insightsQueries=new Map;logGroupCounter=0;filterCounter=0;queryCounter=0;createLogGroup(e){let t=`log-group-${Date.now()}-${this.logGroupCounter++}`,a={id:t,...e};return this.logGroups.set(t,a),a}createLambdaLogGroup(e,t=7){return this.createLogGroup({name:`/aws/lambda/${e}`,retentionDays:t})}createECSLogGroup(e){return this.createLogGroup({name:`/ecs/${e.clusterName}/${e.serviceName}`,retentionDays:e.retentionDays||14})}createAPIGatewayLogGroup(e,t,a=30){return this.createLogGroup({name:`/aws/apigateway/${e}/${t}`,retentionDays:a})}createApplicationLogGroup(e){return this.createLogGroup({name:`/application/${e.appName}/${e.environment}`,retentionDays:e.retentionDays||30,kmsKeyId:e.kmsKeyId})}createMetricFilter(e,t){let a=this.logGroups.get(e);if(!a)throw Error(`Log group not found: ${e}`);let r={id:`filter-${Date.now()}-${this.filterCounter++}`,...t};if(!a.metricFilters)a.metricFilters=[];return a.metricFilters.push(r),r}createErrorCountFilter(e,t){return this.createMetricFilter(e,{name:"ErrorCount",filterPattern:"[timestamp, request_id, level = ERROR*, ...]",metricTransformations:[{metricName:"ErrorCount",metricNamespace:t,metricValue:"1",defaultValue:0,unit:"Count"}]})}createLatencyFilter(e,t){return this.createMetricFilter(e,{name:"Latency",filterPattern:"[timestamp, request_id, level, duration, ...]",metricTransformations:[{metricName:"ResponseTime",metricNamespace:t,metricValue:"$duration",unit:"Milliseconds"}]})}createCustomPatternFilter(e){return this.createMetricFilter(e.logGroupId,{name:e.name,filterPattern:e.pattern,metricTransformations:[{metricName:e.metricName,metricNamespace:e.namespace,metricValue:"1",defaultValue:0,unit:"Count"}]})}createSubscriptionFilter(e,t){let a=this.logGroups.get(e);if(!a)throw Error(`Log group not found: ${e}`);let r={id:`subscription-${Date.now()}-${this.filterCounter++}`,...t};if(!a.subscriptionFilters)a.subscriptionFilters=[];return a.subscriptionFilters.push(r),r}createKinesisSubscription(e){let t=this.logGroups.get(e.logGroupId);if(!t)throw Error(`Log group not found: ${e.logGroupId}`);return this.createSubscriptionFilter(e.logGroupId,{name:"KinesisSubscription",logGroupName:t.name,filterPattern:e.filterPattern||"",destinationArn:e.kinesisStreamArn,roleArn:e.roleArn,distribution:"Random"})}createLambdaSubscription(e){let t=this.logGroups.get(e.logGroupId);if(!t)throw Error(`Log group not found: ${e.logGroupId}`);return this.createSubscriptionFilter(e.logGroupId,{name:"LambdaSubscription",logGroupName:t.name,filterPattern:e.filterPattern||"",destinationArn:e.lambdaFunctionArn,distribution:"ByLogStream"})}createInsightsQuery(e){let t=`query-${Date.now()}-${this.queryCounter++}`,a={id:t,...e};return this.insightsQueries.set(t,a),a}createErrorAnalysisQuery(e){return this.createInsightsQuery({name:"Error Analysis",description:"Analyze error patterns and frequencies",query:`fields @timestamp, @message
|
|
3647
|
+
};`}clear(){this.tests.clear(),this.testCounter=0}}var nm=new Nr;class Dr{rollouts=new Map;flags=new Map;gates=new Map;counter=0;createProgressiveRollout(e,t){let a=`rollout-${Date.now()}-${this.counter++}`,r={id:a,name:e,stages:t,currentStage:0};return this.rollouts.set(a,r),r}createFeatureFlag(e,t=0){let a=`flag-${Date.now()}-${this.counter++}`,r={id:a,name:e,enabled:!1,rolloutPercentage:t,targetingRules:[]};return this.flags.set(a,r),r}createDeploymentGate(e,t,a,r){let n=`gate-${Date.now()}-${this.counter++}`,i={id:n,name:e,type:t,approvers:a,conditions:r};return this.gates.set(n,i),i}clear(){this.rollouts.clear(),this.flags.clear(),this.gates.clear()}}var im=new Dr;class kr{configs=new Map;samplingRules=new Map;configCounter=0;ruleCounter=0;createConfig(e){let t=`xray-config-${Date.now()}-${this.configCounter++}`,a={id:t,...e};return this.configs.set(t,a),a}createLambdaConfig(e){return this.createConfig({name:`${e.functionName}-xray`,serviceName:e.functionName,samplingRate:e.samplingRate||0.1,enableActiveTracing:!0})}createECSConfig(e){return this.createConfig({name:`${e.serviceName}-xray`,serviceName:`${e.clusterName}/${e.serviceName}`,samplingRate:e.samplingRate||0.05,enableActiveTracing:!0})}createAPIGatewayConfig(e){return this.createConfig({name:`${e.apiName}-${e.stage}-xray`,serviceName:`${e.apiName}/${e.stage}`,samplingRate:e.samplingRate||0.05,enableActiveTracing:!0})}createSamplingRule(e){let t=`sampling-rule-${Date.now()}-${this.ruleCounter++}`,a={id:t,...e};return this.samplingRules.set(t,a),a}createHighPrioritySamplingRule(e){return this.createSamplingRule({ruleName:e.ruleName,priority:100,fixedRate:1,reservoirSize:100,serviceName:e.serviceName,serviceType:"*",host:"*",httpMethod:"*",urlPath:e.urlPath,version:1})}createErrorSamplingRule(e){return this.createSamplingRule({ruleName:`${e}-errors`,priority:200,fixedRate:1,reservoirSize:50,serviceName:e,serviceType:"*",host:"*",httpMethod:"*",urlPath:"/error/*",version:1})}createDefaultSamplingRule(e,t=0.05){return this.createSamplingRule({ruleName:`${e}-default`,priority:1000,fixedRate:t,reservoirSize:10,serviceName:e,serviceType:"*",host:"*",httpMethod:"*",urlPath:"*",version:1})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getSamplingRule(e){return this.samplingRules.get(e)}listSamplingRules(){return Array.from(this.samplingRules.values())}generateLambdaXRayCF(e){return{TracingConfig:{Mode:e.enableActiveTracing?"Active":"PassThrough"}}}generateAPIGatewayXRayCF(e){return{TracingEnabled:e.enableActiveTracing}}generateECSXRaySidecarCF(){return{Name:"xray-daemon",Image:"public.ecr.aws/xray/aws-xray-daemon:latest",Cpu:32,MemoryReservation:256,PortMappings:[{ContainerPort:2000,Protocol:"udp"}]}}generateSamplingRuleCF(e){return{Type:"AWS::XRay::SamplingRule",Properties:{SamplingRule:{RuleName:e.ruleName,Priority:e.priority,FixedRate:e.fixedRate,ReservoirSize:e.reservoirSize,ServiceName:e.serviceName,ServiceType:e.serviceType,Host:e.host,HTTPMethod:e.httpMethod,URLPath:e.urlPath,Version:e.version,ResourceARN:"*"}}}}createTrace(e,t){return{id:`trace-${Date.now()}-${this.configCounter++}`,traceId:e,spans:t}}clear(){this.configs.clear(),this.samplingRules.clear(),this.configCounter=0,this.ruleCounter=0}}var sm=new kr;class $r{namespaces=new Map;metrics=new Map;namespaceCounter=0;metricCounter=0;alarmCounter=0;createNamespace(e){let t=`namespace-${Date.now()}-${this.namespaceCounter++}`,a={id:t,...e};return this.namespaces.set(t,a),a}createMetric(e){let t=`metric-${Date.now()}-${this.metricCounter++}`,a={id:t,...e};return this.metrics.set(t,a),a}createBusinessMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:e.unit,dimensions:[{name:"Environment",value:"production"},{name:"Type",value:"Business"}]})}createApplicationMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:e.unit,dimensions:[{name:"Service",value:e.serviceName},{name:"Type",value:"Application"}]})}createPerformanceMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:"Milliseconds",dimensions:[{name:"Operation",value:e.operation},{name:"Type",value:"Performance"}]})}createErrorMetric(e){return this.createMetric({name:e.name,namespace:e.namespace,unit:"Count",dimensions:[{name:"ErrorType",value:e.errorType},{name:"Type",value:"Error"}]})}createAlarm(e,t){let a=this.metrics.get(e);if(!a)throw Error(`Metric not found: ${e}`);let r={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...t};if(!a.alarms)a.alarms=[];return a.alarms.push(r),r}createErrorRateAlarm(e){return this.createAlarm(e.metricId,{name:e.name,description:`Alert when error rate exceeds ${e.threshold} errors/min`,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:2,threshold:e.threshold,period:60,statistic:"Sum",treatMissingData:"notBreaching",actionsEnabled:!0,alarmActions:e.snsTopicArn?[e.snsTopicArn]:void 0})}createLatencyAlarm(e){return this.createAlarm(e.metricId,{name:e.name,description:`Alert when latency exceeds ${e.thresholdMs}ms`,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,threshold:e.thresholdMs,period:300,statistic:"Average",treatMissingData:"notBreaching",actionsEnabled:!0,alarmActions:e.snsTopicArn?[e.snsTopicArn]:void 0})}createThroughputAlarm(e){return this.createAlarm(e.metricId,{name:e.name,description:`Alert when throughput drops below ${e.minimumThreshold}`,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,threshold:e.minimumThreshold,period:300,statistic:"Sum",treatMissingData:"breaching",actionsEnabled:!0,alarmActions:e.snsTopicArn?[e.snsTopicArn]:void 0})}createCompositeAlarm(e){return{name:e.name,description:e.description,alarmRule:e.alarmRule,actionsEnabled:e.actionsEnabled??!0,alarmActions:e.alarmActions}}getNamespace(e){return this.namespaces.get(e)}listNamespaces(){return Array.from(this.namespaces.values())}getMetric(e){return this.metrics.get(e)}listMetrics(){return Array.from(this.metrics.values())}generateAlarmCF(e,t){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:t.name,AlarmDescription:t.description,ComparisonOperator:t.comparisonOperator,EvaluationPeriods:t.evaluationPeriods,MetricName:e.name,Namespace:e.namespace,Period:t.period,Statistic:t.statistic,Threshold:t.threshold,TreatMissingData:t.treatMissingData||"notBreaching",ActionsEnabled:t.actionsEnabled??!0,...t.alarmActions&&{AlarmActions:t.alarmActions},...t.okActions&&{OKActions:t.okActions},...t.insufficientDataActions&&{InsufficientDataActions:t.insufficientDataActions},...e.dimensions&&{Dimensions:e.dimensions.map((a)=>({Name:a.name,Value:a.value}))}}}}generateCompositeAlarmCF(e){return{Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:e.name,AlarmDescription:e.description,AlarmRule:e.alarmRule,ActionsEnabled:e.actionsEnabled,...e.alarmActions&&{AlarmActions:e.alarmActions}}}}generateDashboardWidget(e){return{type:"metric",properties:{metrics:[[e.namespace,e.name,...e.dimensions?.flatMap((t)=>[t.name,t.value])||[]]],period:300,stat:"Average",region:"us-east-1",title:e.name}}}publishCustomMetric(e,t,a,r={},n="Count"){return{id:`metric-${Date.now()}-${this.metricCounter++}`,namespace:e,name:t,dimensions:r,value:a,unit:n,timestamp:new Date}}clear(){this.namespaces.clear(),this.metrics.clear(),this.namespaceCounter=0,this.metricCounter=0,this.alarmCounter=0}}var om=new $r;class Lr{logGroups=new Map;queries=new Map;insightsQueries=new Map;logGroupCounter=0;filterCounter=0;queryCounter=0;createLogGroup(e){let t=`log-group-${Date.now()}-${this.logGroupCounter++}`,a={id:t,...e};return this.logGroups.set(t,a),a}createLambdaLogGroup(e,t=7){return this.createLogGroup({name:`/aws/lambda/${e}`,retentionDays:t})}createECSLogGroup(e){return this.createLogGroup({name:`/ecs/${e.clusterName}/${e.serviceName}`,retentionDays:e.retentionDays||14})}createAPIGatewayLogGroup(e,t,a=30){return this.createLogGroup({name:`/aws/apigateway/${e}/${t}`,retentionDays:a})}createApplicationLogGroup(e){return this.createLogGroup({name:`/application/${e.appName}/${e.environment}`,retentionDays:e.retentionDays||30,kmsKeyId:e.kmsKeyId})}createMetricFilter(e,t){let a=this.logGroups.get(e);if(!a)throw Error(`Log group not found: ${e}`);let r={id:`filter-${Date.now()}-${this.filterCounter++}`,...t};if(!a.metricFilters)a.metricFilters=[];return a.metricFilters.push(r),r}createErrorCountFilter(e,t){return this.createMetricFilter(e,{name:"ErrorCount",filterPattern:"[timestamp, request_id, level = ERROR*, ...]",metricTransformations:[{metricName:"ErrorCount",metricNamespace:t,metricValue:"1",defaultValue:0,unit:"Count"}]})}createLatencyFilter(e,t){return this.createMetricFilter(e,{name:"Latency",filterPattern:"[timestamp, request_id, level, duration, ...]",metricTransformations:[{metricName:"ResponseTime",metricNamespace:t,metricValue:"$duration",unit:"Milliseconds"}]})}createCustomPatternFilter(e){return this.createMetricFilter(e.logGroupId,{name:e.name,filterPattern:e.pattern,metricTransformations:[{metricName:e.metricName,metricNamespace:e.namespace,metricValue:"1",defaultValue:0,unit:"Count"}]})}createSubscriptionFilter(e,t){let a=this.logGroups.get(e);if(!a)throw Error(`Log group not found: ${e}`);let r={id:`subscription-${Date.now()}-${this.filterCounter++}`,...t};if(!a.subscriptionFilters)a.subscriptionFilters=[];return a.subscriptionFilters.push(r),r}createKinesisSubscription(e){let t=this.logGroups.get(e.logGroupId);if(!t)throw Error(`Log group not found: ${e.logGroupId}`);return this.createSubscriptionFilter(e.logGroupId,{name:"KinesisSubscription",logGroupName:t.name,filterPattern:e.filterPattern||"",destinationArn:e.kinesisStreamArn,roleArn:e.roleArn,distribution:"Random"})}createLambdaSubscription(e){let t=this.logGroups.get(e.logGroupId);if(!t)throw Error(`Log group not found: ${e.logGroupId}`);return this.createSubscriptionFilter(e.logGroupId,{name:"LambdaSubscription",logGroupName:t.name,filterPattern:e.filterPattern||"",destinationArn:e.lambdaFunctionArn,distribution:"ByLogStream"})}createInsightsQuery(e){let t=`query-${Date.now()}-${this.queryCounter++}`,a={id:t,...e};return this.insightsQueries.set(t,a),a}createErrorAnalysisQuery(e){return this.createInsightsQuery({name:"Error Analysis",description:"Analyze error patterns and frequencies",query:`fields @timestamp, @message
|
|
3648
3648
|
| filter @message like /ERROR/
|
|
3649
3649
|
| stats count() by bin(5m)
|
|
3650
3650
|
| sort @timestamp desc`,logGroupNames:e})}createLatencyAnalysisQuery(e){return this.createInsightsQuery({name:"Latency Analysis",description:"Analyze request latency patterns",query:`fields @timestamp, @duration
|
|
@@ -3654,7 +3654,7 @@ exports.handler = (event, _context, _callback) => {
|
|
|
3654
3654
|
| filter @message like /ERROR/
|
|
3655
3655
|
| stats count() as error_count by @message
|
|
3656
3656
|
| sort error_count desc
|
|
3657
|
-
| limit 20`,logGroupNames:e})}getLogGroup(e){return this.logGroups.get(e)}listLogGroups(){return Array.from(this.logGroups.values())}getInsightsQuery(e){return this.insightsQueries.get(e)}listInsightsQueries(){return Array.from(this.insightsQueries.values())}generateLogGroupCF(e){return{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:e.name,...e.retentionDays&&{RetentionInDays:e.retentionDays},...e.kmsKeyId&&{KmsKeyId:e.kmsKeyId}}}}generateMetricFilterCF(e,t){return{Type:"AWS::Logs::MetricFilter",Properties:{FilterName:t.name,FilterPattern:t.filterPattern,LogGroupName:e.name,MetricTransformations:t.metricTransformations.map((a)=>({MetricName:a.metricName,MetricNamespace:a.metricNamespace,MetricValue:a.metricValue,...a.defaultValue!==void 0&&{DefaultValue:a.defaultValue},...a.unit&&{Unit:a.unit},...a.dimensions&&{Dimensions:a.dimensions}}))}}}generateSubscriptionFilterCF(e){return{Type:"AWS::Logs::SubscriptionFilter",Properties:{FilterName:e.name,FilterPattern:e.filterPattern,LogGroupName:e.logGroupName,DestinationArn:e.destinationArn,...e.roleArn&&{RoleArn:e.roleArn},...e.distribution&&{Distribution:e.distribution}}}}generateQueryDefinitionCF(e){return{Type:"AWS::Logs::QueryDefinition",Properties:{Name:e.name,QueryString:e.query,LogGroupNames:e.logGroupNames}}}createLogAggregation(e,t,a=7){let r=`aggregation-${Date.now()}-${this.logGroupCounter++}`,n=this.createLogGroup({name:e,retentionDays:a});return t.forEach((i)=>{this.createMetricFilter(n.id,{name:i.metric,filterPattern:i.pattern,metricTransformations:[{metricName:i.metric,metricNamespace:"CustomMetrics",metricValue:"1",defaultValue:0,unit:"Count"}]})}),{id:r,logGroup:e,filters:t,retention:a}}clear(){this.logGroups.clear(),this.queries.clear(),this.insightsQueries.clear(),this.logGroupCounter=0,this.filterCounter=0,this.queryCounter=0}}var
|
|
3657
|
+
| limit 20`,logGroupNames:e})}getLogGroup(e){return this.logGroups.get(e)}listLogGroups(){return Array.from(this.logGroups.values())}getInsightsQuery(e){return this.insightsQueries.get(e)}listInsightsQueries(){return Array.from(this.insightsQueries.values())}generateLogGroupCF(e){return{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:e.name,...e.retentionDays&&{RetentionInDays:e.retentionDays},...e.kmsKeyId&&{KmsKeyId:e.kmsKeyId}}}}generateMetricFilterCF(e,t){return{Type:"AWS::Logs::MetricFilter",Properties:{FilterName:t.name,FilterPattern:t.filterPattern,LogGroupName:e.name,MetricTransformations:t.metricTransformations.map((a)=>({MetricName:a.metricName,MetricNamespace:a.metricNamespace,MetricValue:a.metricValue,...a.defaultValue!==void 0&&{DefaultValue:a.defaultValue},...a.unit&&{Unit:a.unit},...a.dimensions&&{Dimensions:a.dimensions}}))}}}generateSubscriptionFilterCF(e){return{Type:"AWS::Logs::SubscriptionFilter",Properties:{FilterName:e.name,FilterPattern:e.filterPattern,LogGroupName:e.logGroupName,DestinationArn:e.destinationArn,...e.roleArn&&{RoleArn:e.roleArn},...e.distribution&&{Distribution:e.distribution}}}}generateQueryDefinitionCF(e){return{Type:"AWS::Logs::QueryDefinition",Properties:{Name:e.name,QueryString:e.query,LogGroupNames:e.logGroupNames}}}createLogAggregation(e,t,a=7){let r=`aggregation-${Date.now()}-${this.logGroupCounter++}`,n=this.createLogGroup({name:e,retentionDays:a});return t.forEach((i)=>{this.createMetricFilter(n.id,{name:i.metric,filterPattern:i.pattern,metricTransformations:[{metricName:i.metric,metricNamespace:"CustomMetrics",metricValue:"1",defaultValue:0,unit:"Count"}]})}),{id:r,logGroup:e,filters:t,retention:a}}clear(){this.logGroups.clear(),this.queries.clear(),this.insightsQueries.clear(),this.logGroupCounter=0,this.filterCounter=0,this.queryCounter=0}}var cm=new Lr;class Oe{canaries=new Map;heartbeats=new Map;apiMonitors=new Map;canaryCounter=0;heartbeatCounter=0;apiMonitorCounter=0;alarmCounter=0;static RuntimeVersions={NODEJS_PUPPETEER_3_9:"syn-nodejs-puppeteer-3.9",NODEJS_PUPPETEER_4_0:"syn-nodejs-puppeteer-4.0",PYTHON_SELENIUM_1_3:"syn-python-selenium-1.3"};createCanary(e){let t=`canary-${Date.now()}-${this.canaryCounter++}`,a={id:t,...e};return this.canaries.set(t,a),a}createHeartbeatCanary(e){let t=`
|
|
3658
3658
|
const synthetics = require('Synthetics');
|
|
3659
3659
|
const log = require('SyntheticsLogger');
|
|
3660
3660
|
|
|
@@ -3745,35 +3745,35 @@ const workflowCheck = async function () {
|
|
|
3745
3745
|
exports.handler = async () => {
|
|
3746
3746
|
return await workflowCheck();
|
|
3747
3747
|
};
|
|
3748
|
-
`;return this.createCanary({name:e.name,description:e.description,runtimeVersion:Oe.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:t},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:180,memoryInMB:1024,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}generateActionScript(e){switch(e.type){case"click":return`await page.click('${e.selector}');`;case"type":return`await page.type('${e.selector}', '${e.value}');`;case"wait":return`await page.waitForTimeout(${e.duration});`;case"waitForSelector":return`await page.waitForSelector('${e.selector}');`;default:return""}}createAlarm(e,t){let a=this.canaries.get(e);if(!a)throw Error(`Canary not found: ${e}`);let r={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...t};if(!a.alarms)a.alarms=[];return a.alarms.push(r),r}getCanary(e){return this.canaries.get(e)}listCanaries(){return Array.from(this.canaries.values())}generateCanaryCF(e){let t={Type:"AWS::Synthetics::Canary",Properties:{Name:e.name,RuntimeVersion:e.runtimeVersion,ExecutionRoleArn:{"Fn::GetAtt":["CanaryExecutionRole","Arn"]},Schedule:{Expression:e.schedule.expression,...e.schedule.durationInSeconds&&{DurationInSeconds:e.schedule.durationInSeconds}},ArtifactS3Location:e.artifactS3Location,StartCanaryAfterCreation:!0}};if(e.code.type==="script")t.Properties.Code={Handler:e.handler,Script:e.code.script};else t.Properties.Code={Handler:e.handler,S3Bucket:e.code.s3Bucket,S3Key:e.code.s3Key,...e.code.s3Version&&{S3ObjectVersion:e.code.s3Version}};if(e.runConfig)t.Properties.RunConfig={TimeoutInSeconds:e.runConfig.timeoutInSeconds,MemoryInMB:e.runConfig.memoryInMB,...e.runConfig.environmentVariables&&{EnvironmentVariables:e.runConfig.environmentVariables},...e.runConfig.activeTracing!==void 0&&{ActiveTracing:e.runConfig.activeTracing}};if(e.vpcConfig)t.Properties.VPCConfig={SubnetIds:e.vpcConfig.subnetIds,SecurityGroupIds:e.vpcConfig.securityGroupIds};if(e.successRetentionPeriod)t.Properties.SuccessRetentionPeriod=e.successRetentionPeriod;if(e.failureRetentionPeriod)t.Properties.FailureRetentionPeriod=e.failureRetentionPeriod;return t}generateCanaryRoleCF(){return{Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole","arn:aws:iam::aws:policy/CloudWatchSyntheticsFullAccess"],Policies:[{PolicyName:"CanaryS3Policy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:PutObject","s3:GetBucketLocation"],Resource:["arn:aws:s3:::*/*"]}]}}]}}}clear(){this.canaries.clear(),this.heartbeats.clear(),this.apiMonitors.clear(),this.canaryCounter=0,this.heartbeatCounter=0,this.apiMonitorCounter=0,this.alarmCounter=0}}var
|
|
3748
|
+
`;return this.createCanary({name:e.name,description:e.description,runtimeVersion:Oe.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:t},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:180,memoryInMB:1024,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}generateActionScript(e){switch(e.type){case"click":return`await page.click('${e.selector}');`;case"type":return`await page.type('${e.selector}', '${e.value}');`;case"wait":return`await page.waitForTimeout(${e.duration});`;case"waitForSelector":return`await page.waitForSelector('${e.selector}');`;default:return""}}createAlarm(e,t){let a=this.canaries.get(e);if(!a)throw Error(`Canary not found: ${e}`);let r={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...t};if(!a.alarms)a.alarms=[];return a.alarms.push(r),r}getCanary(e){return this.canaries.get(e)}listCanaries(){return Array.from(this.canaries.values())}generateCanaryCF(e){let t={Type:"AWS::Synthetics::Canary",Properties:{Name:e.name,RuntimeVersion:e.runtimeVersion,ExecutionRoleArn:{"Fn::GetAtt":["CanaryExecutionRole","Arn"]},Schedule:{Expression:e.schedule.expression,...e.schedule.durationInSeconds&&{DurationInSeconds:e.schedule.durationInSeconds}},ArtifactS3Location:e.artifactS3Location,StartCanaryAfterCreation:!0}};if(e.code.type==="script")t.Properties.Code={Handler:e.handler,Script:e.code.script};else t.Properties.Code={Handler:e.handler,S3Bucket:e.code.s3Bucket,S3Key:e.code.s3Key,...e.code.s3Version&&{S3ObjectVersion:e.code.s3Version}};if(e.runConfig)t.Properties.RunConfig={TimeoutInSeconds:e.runConfig.timeoutInSeconds,MemoryInMB:e.runConfig.memoryInMB,...e.runConfig.environmentVariables&&{EnvironmentVariables:e.runConfig.environmentVariables},...e.runConfig.activeTracing!==void 0&&{ActiveTracing:e.runConfig.activeTracing}};if(e.vpcConfig)t.Properties.VPCConfig={SubnetIds:e.vpcConfig.subnetIds,SecurityGroupIds:e.vpcConfig.securityGroupIds};if(e.successRetentionPeriod)t.Properties.SuccessRetentionPeriod=e.successRetentionPeriod;if(e.failureRetentionPeriod)t.Properties.FailureRetentionPeriod=e.failureRetentionPeriod;return t}generateCanaryRoleCF(){return{Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole","arn:aws:iam::aws:policy/CloudWatchSyntheticsFullAccess"],Policies:[{PolicyName:"CanaryS3Policy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:PutObject","s3:GetBucketLocation"],Resource:["arn:aws:s3:::*/*"]}]}}]}}}clear(){this.canaries.clear(),this.heartbeats.clear(),this.apiMonitors.clear(),this.canaryCounter=0,this.heartbeatCounter=0,this.apiMonitorCounter=0,this.alarmCounter=0}}var lm=new Oe;class Mr{plans=new Map;migrations=new Map;planCounter=0;migrationCounter=0;createPlan(e){let t=`migration-plan-${Date.now()}-${this.planCounter++}`,a={id:t,...e};return this.plans.set(t,a),a}createMigration(e){let t=`migration-${Date.now()}-${this.migrationCounter++}`,a=this.generateChecksum(e.up+e.down),r={id:t,checksum:a,...e};return this.migrations.set(t,r),r}createSchemaMigration(e){let{up:t,down:a}=this.generateSchemaSQL(e.changes,e.tableName,e.engine);return this.createMigration({version:e.version,name:e.name,description:`Schema changes for ${e.tableName}`,up:t,down:a})}createDataMigration(e){return this.createMigration({version:e.version,name:e.name,description:e.description,up:e.upSQL,down:e.downSQL})}addMigrationToPlan(e,t){let a=this.plans.get(e);if(!a)throw Error(`Migration plan not found: ${e}`);a.migrations.push(t)}async executePlan(e,t=!1){let a=this.plans.get(e);if(!a)throw Error(`Migration plan not found: ${e}`);let r=Date.now(),n=[],i=[];if(console.log(`${t?"[DRY RUN] ":""}Executing migration plan: ${a.name}`),console.log(`Database: ${a.database.type} - ${a.database.identifier}`),console.log(`Migrations to apply: ${a.migrations.length}
|
|
3749
3749
|
`),a.backupBeforeMigration&&!t)console.log("Creating database backup before migration...");for(let o of a.migrations)try{if(console.log(`Applying migration: ${o.version} - ${o.name}`),!t){if(this.generateChecksum(o.up+o.down)!==o.checksum)throw Error("Migration checksum mismatch - migration has been modified");let c=Date.now();o.appliedAt=new Date,o.executionTimeMs=Date.now()-c,console.log(`✓ Applied in ${o.executionTimeMs}ms
|
|
3750
3750
|
`)}else console.log(`[SKIPPED - DRY RUN]
|
|
3751
3751
|
`);n.push(o.version)}catch(c){if(console.error(`✗ Failed: ${c instanceof Error?c.message:String(c)}
|
|
3752
3752
|
`),i.push(o.version),!t)return console.log("Rolling back previously applied migrations..."),await this.rollbackMigrations(n.reverse(),a),{success:!1,version:o.version,appliedMigrations:[],failedMigrations:i,executionTimeMs:Date.now()-r,error:c instanceof Error?c.message:String(c),rollbackPerformed:!0}}let s=Date.now()-r;return console.log(`${t?"[DRY RUN] ":""}Migration plan completed successfully`),console.log(`Total time: ${s}ms`),{success:!0,version:a.migrations[a.migrations.length-1]?.version||"unknown",appliedMigrations:n,failedMigrations:i,executionTimeMs:s}}async rollbackMigrations(e,t){for(let a of e){let r=t.migrations.find((n)=>n.version===a);if(r)console.log(`Rolling back: ${r.version} - ${r.name}`),r.rolledBackAt=new Date,console.log(`✓ Rolled back
|
|
3753
3753
|
`)}}getMigrationStatus(e){let t=this.plans.get(e);if(!t)throw Error(`Migration plan not found: ${e}`);let a=t.migrations.filter((n)=>n.appliedAt&&!n.rolledBackAt),r=t.migrations.filter((n)=>!n.appliedAt);return{currentVersion:a[a.length-1]?.version||"0.0.0",pendingMigrations:r,appliedMigrations:a,lastMigration:a[a.length-1]}}generateSchemaSQL(e,t,a="postgres"){let r=[],n=[];for(let i of e)switch(i.type){case"add_column":r.push(`ALTER TABLE ${t} ADD COLUMN ${i.columnName} ${i.columnType}${i.nullable===!1?" NOT NULL":""}${i.defaultValue?` DEFAULT ${i.defaultValue}`:""}; `),n.push(`ALTER TABLE ${t} DROP COLUMN ${i.columnName};`);break;case"drop_column":r.push(`ALTER TABLE ${t} DROP COLUMN ${i.columnName};`),n.push(`-- Cannot restore dropped column ${i.columnName}`);break;case"modify_column":if(a==="postgres")r.push(`ALTER TABLE ${t} ALTER COLUMN ${i.columnName} TYPE ${i.newType};`);else r.push(`ALTER TABLE ${t} MODIFY COLUMN ${i.columnName} ${i.newType};`);n.push(`-- Reverting ${i.columnName} type change requires manual intervention`);break;case"add_index":r.push(`CREATE INDEX ${i.indexName} ON ${t} (${(i.columns??[]).join(", ")});`),n.push(`DROP INDEX ${i.indexName};`);break;case"drop_index":r.push(`DROP INDEX ${i.indexName};`),n.push(`-- Cannot restore index ${i.indexName} without schema details`);break}return{up:r.join(`
|
|
3754
3754
|
`),down:n.reverse().join(`
|
|
3755
|
-
`)}}generateChecksum(e){let t=0;for(let a=0;a<e.length;a++){let r=e.charCodeAt(a);t=(t<<5)-t+r,t=t&t}return t.toString(16)}validatePlan(e){let t=this.plans.get(e);if(!t)return{valid:!1,errors:["Migration plan not found"]};let a=[],r=new Set;for(let n of t.migrations){if(r.has(n.version))a.push(`Duplicate migration version: ${n.version}`);r.add(n.version)}for(let n of t.migrations)if(!n.down||n.down.trim()==="")a.push(`Migration ${n.version} is missing rollback SQL`);for(let n of t.migrations)if(this.generateChecksum(n.up+n.down)!==n.checksum)a.push(`Migration ${n.version} has invalid checksum`);return{valid:a.length===0,errors:a}}getPlan(e){return this.plans.get(e)}listPlans(){return Array.from(this.plans.values())}getMigration(e){return this.migrations.get(e)}listMigrations(){return Array.from(this.migrations.values())}clear(){this.plans.clear(),this.migrations.clear(),this.planCounter=0,this.migrationCounter=0}}var
|
|
3755
|
+
`)}}generateChecksum(e){let t=0;for(let a=0;a<e.length;a++){let r=e.charCodeAt(a);t=(t<<5)-t+r,t=t&t}return t.toString(16)}validatePlan(e){let t=this.plans.get(e);if(!t)return{valid:!1,errors:["Migration plan not found"]};let a=[],r=new Set;for(let n of t.migrations){if(r.has(n.version))a.push(`Duplicate migration version: ${n.version}`);r.add(n.version)}for(let n of t.migrations)if(!n.down||n.down.trim()==="")a.push(`Migration ${n.version} is missing rollback SQL`);for(let n of t.migrations)if(this.generateChecksum(n.up+n.down)!==n.checksum)a.push(`Migration ${n.version} has invalid checksum`);return{valid:a.length===0,errors:a}}getPlan(e){return this.plans.get(e)}listPlans(){return Array.from(this.plans.values())}getMigration(e){return this.migrations.get(e)}listMigrations(){return Array.from(this.migrations.values())}clear(){this.plans.clear(),this.migrations.clear(),this.planCounter=0,this.migrationCounter=0}}var um=new Mr;class xr{replicas=new Map;replicationGroups=new Map;proxies=new Map;proxyTargets=new Map;replicaCounter=0;groupCounter=0;proxyCounter=0;targetCounter=0;createReplica(e){let t=`replica-${Date.now()}-${this.replicaCounter++}`,a={id:t,status:"creating",...e};return this.replicas.set(t,a),a}createRDSReplica(e){return this.createReplica({name:e.name,sourceDatabase:e.sourceDatabase,region:e.region||"us-east-1",instanceClass:e.instanceClass||"db.t3.medium",multiAZ:e.multiAZ||!1,autoMinorVersionUpgrade:!0,backupRetentionPeriod:7})}createCrossRegionReplica(e){return this.createReplica({name:e.name,sourceDatabase:e.sourceDatabase,region:e.targetRegion,instanceClass:e.instanceClass||"db.t3.medium",multiAZ:!0,autoMinorVersionUpgrade:!0,backupRetentionPeriod:7})}createReplicationGroup(e){let t=`replication-group-${Date.now()}-${this.groupCounter++}`,a={id:t,...e};return this.replicationGroups.set(t,a),a}createAutoScalingReplicationGroup(e){return this.createReplicationGroup({name:e.name,primaryDatabase:e.primaryDatabase,replicas:[],loadBalancing:e.loadBalancing||{type:"round-robin"},failoverEnabled:!0,autoScaling:{enabled:!0,minReplicas:e.minReplicas,maxReplicas:e.maxReplicas,targetCPU:e.targetCPU||70,scaleUpCooldown:300,scaleDownCooldown:600}})}addReplicaToGroup(e,t){let a=this.replicationGroups.get(e);if(!a)throw Error(`Replication group not found: ${e}`);a.replicas.push(t)}createProxy(e){let t=`rds-proxy-${Date.now()}-${this.proxyCounter++}`,a={id:t,...e};return this.proxies.set(t,a),a}createConnectionPoolProxy(e){return this.createProxy({name:e.name,engineFamily:e.engineFamily,targetDatabase:e.targetDatabase,maxConnectionsPercent:e.maxConnections||100,maxIdleConnectionsPercent:50,connectionBorrowTimeout:120,sessionPinningFilters:["EXCLUDE_VARIABLE_SETS"],requireTLS:!0,idleClientTimeout:1800,vpcSubnetIds:e.vpcSubnetIds,securityGroupIds:e.securityGroupIds,secretArn:e.secretArn})}createServerlessProxy(e){return this.createProxy({name:e.name,engineFamily:e.engineFamily,targetDatabase:e.targetDatabase,maxConnectionsPercent:100,maxIdleConnectionsPercent:10,connectionBorrowTimeout:60,sessionPinningFilters:["EXCLUDE_VARIABLE_SETS"],requireTLS:!0,idleClientTimeout:300,vpcSubnetIds:e.vpcSubnetIds,securityGroupIds:e.securityGroupIds,secretArn:e.secretArn})}addProxyTarget(e){let t=`proxy-target-${Date.now()}-${this.targetCounter++}`,a={id:t,...e};return this.proxyTargets.set(t,a),a}promoteReplica(e){let t=this.replicas.get(e);if(!t)return{success:!1,message:"Replica not found"};if(console.log(`Promoting replica to primary: ${t.name}`),console.log(`Region: ${t.region}`),console.log(`
|
|
3756
3756
|
1. Checking replication lag...`),t.replicationLag&&t.replicationLag>5000)return{success:!1,message:`Replication lag too high: ${t.replicationLag}ms`};return console.log(` Replication lag: ${t.replicationLag||0}ms (acceptable)`),console.log(`
|
|
3757
3757
|
2. Promoting replica to standalone instance...`),console.log(`
|
|
3758
3758
|
3. Updating DNS records...`),console.log(`
|
|
3759
3759
|
4. Updating application configuration...`),console.log(`
|
|
3760
|
-
✓ Promotion completed successfully`),t.status="available",{success:!0,message:"Replica promoted successfully"}}getReplicationLag(e){if(!this.replicas.get(e))throw Error(`Replica not found: ${e}`);return Math.floor(Math.random()*1000)}getReplica(e){return this.replicas.get(e)}listReplicas(){return Array.from(this.replicas.values())}getReplicationGroup(e){return this.replicationGroups.get(e)}listReplicationGroups(){return Array.from(this.replicationGroups.values())}getProxy(e){return this.proxies.get(e)}listProxies(){return Array.from(this.proxies.values())}generateReplicaCF(e){return{Type:"AWS::RDS::DBInstance",Properties:{SourceDBInstanceIdentifier:e.sourceDatabase,DBInstanceIdentifier:e.name,DBInstanceClass:e.instanceClass,MultiAZ:e.multiAZ||!1,AutoMinorVersionUpgrade:e.autoMinorVersionUpgrade??!0,...e.backupRetentionPeriod&&{BackupRetentionPeriod:e.backupRetentionPeriod},...e.preferredBackupWindow&&{PreferredBackupWindow:e.preferredBackupWindow},...e.preferredMaintenanceWindow&&{PreferredMaintenanceWindow:e.preferredMaintenanceWindow}}}}generateProxyCF(e){return{Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:e.name,EngineFamily:e.engineFamily,Auth:[{AuthScheme:"SECRETS",SecretArn:e.secretArn,IAMAuth:"DISABLED"}],RoleArn:{"Fn::GetAtt":["RDSProxyRole","Arn"]},VpcSubnetIds:e.vpcSubnetIds,VpcSecurityGroupIds:e.securityGroupIds,RequireTLS:e.requireTLS??!0,IdleClientTimeout:e.idleClientTimeout||1800,...e.maxConnectionsPercent&&{MaxConnectionsPercent:e.maxConnectionsPercent},...e.maxIdleConnectionsPercent&&{MaxIdleConnectionsPercent:e.maxIdleConnectionsPercent},...e.connectionBorrowTimeout&&{ConnectionBorrowTimeout:e.connectionBorrowTimeout}}}}generateProxyTargetCF(e,t){return{Type:"AWS::RDS::DBProxyTargetGroup",Properties:{DBProxyName:t.name,TargetGroupName:"default",DBInstanceIdentifiers:[e.targetArn],ConnectionPoolConfig:{MaxConnectionsPercent:100,MaxIdleConnectionsPercent:50,ConnectionBorrowTimeout:120}}}}generateProxyRoleCF(){return{Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"RDSProxySecretsPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],Resource:"arn:aws:secretsmanager:*:*:secret:*"},{Effect:"Allow",Action:["kms:Decrypt"],Resource:"arn:aws:kms:*:*:key/*",Condition:{StringEquals:{"kms:ViaService":"secretsmanager.*.amazonaws.com"}}}]}}]}}}clear(){this.replicas.clear(),this.replicationGroups.clear(),this.proxies.clear(),this.proxyTargets.clear(),this.replicaCounter=0,this.groupCounter=0,this.proxyCounter=0,this.targetCounter=0}}var um=new xr;class Or{insights=new Map;slowQueryLogs=new Map;queryMetrics=new Map;reports=new Map;indexRecommendations=new Map;insightsCounter=0;logCounter=0;metricCounter=0;reportCounter=0;recommendationCounter=0;enablePerformanceInsights(e){let t=`pi-${Date.now()}-${this.insightsCounter++}`,a={id:t,name:e.name,databaseIdentifier:e.databaseIdentifier,enabled:!0,retentionPeriod:e.retentionPeriod||7,kmsKeyId:e.kmsKeyId};return this.insights.set(t,a),a}enableSlowQueryLog(e){let t=`slow-query-${Date.now()}-${this.logCounter++}`,a={id:t,name:e.name,databaseIdentifier:e.databaseIdentifier,enabled:!0,logDestination:e.logDestination,cloudwatchLogGroup:e.cloudwatchLogGroup,s3Bucket:e.s3Bucket,s3Prefix:e.s3Bucket?"slow-queries/":void 0,minExecutionTime:e.minExecutionTime||1000};return this.slowQueryLogs.set(t,a),a}recordQueryMetric(e){let t=`metric-${Date.now()}-${this.metricCounter++}`,a={id:t,timestamp:new Date,...e};return this.queryMetrics.set(t,a),a}generatePerformanceReport(e){let t=`report-${Date.now()}-${this.reportCounter++}`,a={avgCPU:Math.random()*60+20,maxCPU:Math.random()*30+70,avgConnections:Math.floor(Math.random()*50+10),maxConnections:Math.floor(Math.random()*50+100),avgReadIOPS:Math.floor(Math.random()*1000+500),avgWriteIOPS:Math.floor(Math.random()*500+200),avgReadThroughput:Math.random()*50+10,avgWriteThroughput:Math.random()*20+5,avgReadLatency:Math.random()*5+1,avgWriteLatency:Math.random()*8+2,cacheHitRatio:Math.random()*10+90,deadlocks:Math.floor(Math.random()*5),longRunningTransactions:Math.floor(Math.random()*10)},r=Array.from(this.queryMetrics.values()),n=r.sort((c,l)=>l.executionCount-c.executionCount).slice(0,10),i=r.filter((c)=>c.avgExecutionTime>1000).sort((c,l)=>l.avgExecutionTime-c.avgExecutionTime).slice(0,10),s=this.generateRecommendations(a,i),o={id:t,name:e.name,databaseIdentifier:e.databaseIdentifier,reportType:e.reportType,metrics:a,topQueries:n,slowQueries:i,recommendations:s,generatedAt:new Date};return this.reports.set(t,o),o}generateRecommendations(e,t){let a=[];if(e.avgCPU>70)a.push({type:"scaling",severity:"high",title:"High CPU Usage",description:`Average CPU usage is ${e.avgCPU.toFixed(1)}%, which is above the recommended threshold of 70%.`,impact:"Performance degradation, increased latency, potential timeouts",effort:"medium"});if(e.cacheHitRatio<95)a.push({type:"configuration",severity:"medium",title:"Low Cache Hit Ratio",description:`Cache hit ratio is ${e.cacheHitRatio.toFixed(1)}%. Consider increasing buffer pool size.`,impact:"Increased disk I/O, slower query performance",effort:"low"});if(e.deadlocks>0)a.push({type:"query",severity:"medium",title:"Deadlocks Detected",description:`${e.deadlocks} deadlock(s) detected. Review transaction isolation levels and query patterns.`,impact:"Transaction failures, application errors",effort:"high"});if(t.length>0)a.push({type:"index",severity:"high",title:"Slow Queries Detected",description:`${t.length} slow queries detected. Consider adding indexes or optimizing queries.`,impact:"High latency, poor user experience",effort:"medium"});if(e.avgReadLatency>10||e.avgWriteLatency>10)a.push({type:"scaling",severity:"high",title:"High I/O Latency",description:"Read or write latency is high. Consider upgrading to Provisioned IOPS or moving to a larger instance.",impact:"Slow query execution, application timeouts",effort:"medium"});return a}analyzeQuery(e){let t=`analysis-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,a=[{id:1,operation:"Seq Scan",table:"users",rows:1e4,cost:850.5,children:[]}],r=[];if(e.toLowerCase().includes("select *"))r.push({type:"full_table_scan",severity:"warning",description:"Query selects all columns. Consider selecting only required columns."});if(!e.toLowerCase().includes("where")&&e.toLowerCase().includes("select"))r.push({type:"full_table_scan",severity:"critical",description:"Query has no WHERE clause and may scan entire table."});return{id:t,queryId:t,sql:e,executionPlan:a,bottlenecks:r,recommendations:["Add appropriate indexes on WHERE clause columns","Consider using EXPLAIN ANALYZE to get actual execution statistics","Review and optimize JOIN conditions"],estimatedCost:a[0].cost}}recommendIndex(e){let t=`index-rec-${Date.now()}-${this.recommendationCounter++}`,a=`idx_${e.tableName}_${e.columns.join("_")}`,r={id:t,tableName:e.tableName,columns:e.columns,reason:e.reason,estimatedImprovement:e.estimatedImprovement||50,estimatedSize:e.columns.length*10,createSQL:`CREATE INDEX ${a} ON ${e.tableName} (${e.columns.join(", ")});`};return this.indexRecommendations.set(t,r),r}getInsights(e){return this.insights.get(e)}listInsights(){return Array.from(this.insights.values())}getSlowQueryLog(e){return this.slowQueryLogs.get(e)}listSlowQueryLogs(){return Array.from(this.slowQueryLogs.values())}getReport(e){return this.reports.get(e)}listReports(){return Array.from(this.reports.values())}listIndexRecommendations(){return Array.from(this.indexRecommendations.values())}generatePerformanceInsightsCF(e){return{EnablePerformanceInsights:e.enabled,PerformanceInsightsRetentionPeriod:e.retentionPeriod,...e.kmsKeyId&&{PerformanceInsightsKMSKeyId:e.kmsKeyId}}}generateSlowQueryAlarmCF(e){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:"Alert when slow queries exceed threshold",MetricName:"SlowQueryCount",Namespace:"AWS/RDS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",...e.snsTopicArn&&{AlarmActions:[e.snsTopicArn]}}}}clear(){this.insights.clear(),this.slowQueryLogs.clear(),this.queryMetrics.clear(),this.reports.clear(),this.indexRecommendations.clear(),this.insightsCounter=0,this.logCounter=0,this.metricCounter=0,this.reportCounter=0,this.recommendationCounter=0}}var dm=new Or;class Wr{users=new Map;roles=new Map;audits=new Map;userCounter=0;roleCounter=0;auditCounter=0;createUser(e){let t=`db-user-${Date.now()}-${this.userCounter++}`,a={id:t,createdAt:new Date,...e};return this.users.set(t,a),a}createReadOnlyUser(e){let t=e.tables?e.tables.map((a)=>({database:e.database,table:a,privileges:["SELECT"]})):[{database:e.database,privileges:["SELECT"]}];return this.createUser({username:e.username,database:e.database,privileges:t,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:90})}createReadWriteUser(e){let t=e.tables?e.tables.map((a)=>({database:e.database,table:a,privileges:["SELECT","INSERT","UPDATE","DELETE"]})):[{database:e.database,privileges:["SELECT","INSERT","UPDATE","DELETE"]}];return this.createUser({username:e.username,database:e.database,privileges:t,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:60})}createAdminUser(e){return this.createUser({username:e.username,database:e.database,privileges:[{database:e.database,privileges:["ALL"]}],passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:30})}createApplicationUser(e){let t=e.tables.map((a)=>({database:e.database,table:a.name,privileges:a.privileges}));return this.createUser({username:e.username,database:e.database,privileges:t,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:90})}createRole(e){let t=`role-${Date.now()}-${this.roleCounter++}`,a={id:t,users:[],...e};return this.roles.set(t,a),a}assignUserToRole(e,t){let a=this.users.get(e),r=this.roles.get(t);if(!a)throw Error(`User not found: ${e}`);if(!r)throw Error(`Role not found: ${t}`);r.users.push(e);for(let n of r.privileges){let i=a.privileges.find((s)=>s.database===n.database&&s.table===n.table);if(i)i.privileges=Array.from(new Set([...i.privileges,...n.privileges]));else a.privileges.push({...n})}}grantPrivileges(e,t){let a=this.users.get(e);if(!a)return{success:!1,message:"User not found"};for(let r of t){let n=a.privileges.find((i)=>i.database===r.database&&i.table===r.table);if(n)n.privileges=Array.from(new Set([...n.privileges,...r.privileges]));else a.privileges.push(r)}return this.auditAccess({username:a.username,action:"GRANT",database:t[0]?.database,table:t[0]?.table,success:!0}),{success:!0,message:"Privileges granted successfully"}}revokePrivileges(e,t){let a=this.users.get(e);if(!a)return{success:!1,message:"User not found"};for(let r of t){let n=a.privileges.findIndex((i)=>i.database===r.database&&i.table===r.table);if(n!==-1){let i=a.privileges[n];if(i.privileges=i.privileges.filter((s)=>!r.privileges.includes(s)),i.privileges.length===0)a.privileges.splice(n,1)}}return this.auditAccess({username:a.username,action:"REVOKE",database:t[0]?.database,table:t[0]?.table,success:!0}),{success:!0,message:"Privileges revoked successfully"}}rotatePassword(e){let t=this.users.get(e);if(!t)return{success:!1};let a=`arn:aws:secretsmanager:us-east-1:123456789012:secret:db-${t.username}-${Date.now()}`;return t.passwordSecretArn=a,t.lastRotated=new Date,console.log(`Password rotated for user: ${t.username}`),{success:!0,newSecretArn:a}}needsPasswordRotation(e){let t=this.users.get(e);if(!t||!t.rotationEnabled||!t.lastRotated||!t.rotationDays)return!1;return(Date.now()-t.lastRotated.getTime())/86400000>=t.rotationDays}auditAccess(e){let t=`audit-${Date.now()}-${this.auditCounter++}`,a={id:t,timestamp:new Date,...e};return this.audits.set(t,a),a}getUserAccessHistory(e,t=100){return Array.from(this.audits.values()).filter((a)=>a.username===e).sort((a,r)=>r.timestamp.getTime()-a.timestamp.getTime()).slice(0,t)}getFailedLoginAttempts(e,t=24){let a=Date.now()-t*60*60*1000;return Array.from(this.audits.values()).filter((r)=>r.username===e&&r.action==="LOGIN"&&!r.success&&r.timestamp.getTime()>a)}generateCreateUserSQL(e,t="postgres"){let a=[];if(t==="postgres"){a.push(`CREATE USER ${e.username} WITH PASSWORD '${e.passwordSecretArn}';`);for(let r of e.privileges)if(r.privileges.includes("ALL"))a.push(`GRANT ALL PRIVILEGES ON DATABASE ${r.database} TO ${e.username};`);else{let n=r.privileges.join(", ");if(r.table)a.push(`GRANT ${n} ON ${r.database}.${r.table} TO ${e.username};`);else a.push(`GRANT ${n} ON DATABASE ${r.database} TO ${e.username};`)}}else{a.push(`CREATE USER '${e.username}'@'%' IDENTIFIED BY '${e.passwordSecretArn}';`);for(let r of e.privileges){let n=r.privileges.includes("ALL")?"ALL PRIVILEGES":r.privileges.join(", "),i=r.table?`${r.database}.${r.table}`:`${r.database}.*`;a.push(`GRANT ${n} ON ${i} TO '${e.username}'@'%';`)}a.push("FLUSH PRIVILEGES;")}return a.join(`
|
|
3761
|
-
`)}getUser(e){return this.users.get(e)}listUsers(){return Array.from(this.users.values())}getRole(e){return this.roles.get(e)}listRoles(){return Array.from(this.roles.values())}clear(){this.users.clear(),this.roles.clear(),this.audits.clear(),this.userCounter=0,this.roleCounter=0,this.auditCounter=0}}var
|
|
3760
|
+
✓ Promotion completed successfully`),t.status="available",{success:!0,message:"Replica promoted successfully"}}getReplicationLag(e){if(!this.replicas.get(e))throw Error(`Replica not found: ${e}`);return Math.floor(Math.random()*1000)}getReplica(e){return this.replicas.get(e)}listReplicas(){return Array.from(this.replicas.values())}getReplicationGroup(e){return this.replicationGroups.get(e)}listReplicationGroups(){return Array.from(this.replicationGroups.values())}getProxy(e){return this.proxies.get(e)}listProxies(){return Array.from(this.proxies.values())}generateReplicaCF(e){return{Type:"AWS::RDS::DBInstance",Properties:{SourceDBInstanceIdentifier:e.sourceDatabase,DBInstanceIdentifier:e.name,DBInstanceClass:e.instanceClass,MultiAZ:e.multiAZ||!1,AutoMinorVersionUpgrade:e.autoMinorVersionUpgrade??!0,...e.backupRetentionPeriod&&{BackupRetentionPeriod:e.backupRetentionPeriod},...e.preferredBackupWindow&&{PreferredBackupWindow:e.preferredBackupWindow},...e.preferredMaintenanceWindow&&{PreferredMaintenanceWindow:e.preferredMaintenanceWindow}}}}generateProxyCF(e){return{Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:e.name,EngineFamily:e.engineFamily,Auth:[{AuthScheme:"SECRETS",SecretArn:e.secretArn,IAMAuth:"DISABLED"}],RoleArn:{"Fn::GetAtt":["RDSProxyRole","Arn"]},VpcSubnetIds:e.vpcSubnetIds,VpcSecurityGroupIds:e.securityGroupIds,RequireTLS:e.requireTLS??!0,IdleClientTimeout:e.idleClientTimeout||1800,...e.maxConnectionsPercent&&{MaxConnectionsPercent:e.maxConnectionsPercent},...e.maxIdleConnectionsPercent&&{MaxIdleConnectionsPercent:e.maxIdleConnectionsPercent},...e.connectionBorrowTimeout&&{ConnectionBorrowTimeout:e.connectionBorrowTimeout}}}}generateProxyTargetCF(e,t){return{Type:"AWS::RDS::DBProxyTargetGroup",Properties:{DBProxyName:t.name,TargetGroupName:"default",DBInstanceIdentifiers:[e.targetArn],ConnectionPoolConfig:{MaxConnectionsPercent:100,MaxIdleConnectionsPercent:50,ConnectionBorrowTimeout:120}}}}generateProxyRoleCF(){return{Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"RDSProxySecretsPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],Resource:"arn:aws:secretsmanager:*:*:secret:*"},{Effect:"Allow",Action:["kms:Decrypt"],Resource:"arn:aws:kms:*:*:key/*",Condition:{StringEquals:{"kms:ViaService":"secretsmanager.*.amazonaws.com"}}}]}}]}}}clear(){this.replicas.clear(),this.replicationGroups.clear(),this.proxies.clear(),this.proxyTargets.clear(),this.replicaCounter=0,this.groupCounter=0,this.proxyCounter=0,this.targetCounter=0}}var dm=new xr;class Or{insights=new Map;slowQueryLogs=new Map;queryMetrics=new Map;reports=new Map;indexRecommendations=new Map;insightsCounter=0;logCounter=0;metricCounter=0;reportCounter=0;recommendationCounter=0;enablePerformanceInsights(e){let t=`pi-${Date.now()}-${this.insightsCounter++}`,a={id:t,name:e.name,databaseIdentifier:e.databaseIdentifier,enabled:!0,retentionPeriod:e.retentionPeriod||7,kmsKeyId:e.kmsKeyId};return this.insights.set(t,a),a}enableSlowQueryLog(e){let t=`slow-query-${Date.now()}-${this.logCounter++}`,a={id:t,name:e.name,databaseIdentifier:e.databaseIdentifier,enabled:!0,logDestination:e.logDestination,cloudwatchLogGroup:e.cloudwatchLogGroup,s3Bucket:e.s3Bucket,s3Prefix:e.s3Bucket?"slow-queries/":void 0,minExecutionTime:e.minExecutionTime||1000};return this.slowQueryLogs.set(t,a),a}recordQueryMetric(e){let t=`metric-${Date.now()}-${this.metricCounter++}`,a={id:t,timestamp:new Date,...e};return this.queryMetrics.set(t,a),a}generatePerformanceReport(e){let t=`report-${Date.now()}-${this.reportCounter++}`,a={avgCPU:Math.random()*60+20,maxCPU:Math.random()*30+70,avgConnections:Math.floor(Math.random()*50+10),maxConnections:Math.floor(Math.random()*50+100),avgReadIOPS:Math.floor(Math.random()*1000+500),avgWriteIOPS:Math.floor(Math.random()*500+200),avgReadThroughput:Math.random()*50+10,avgWriteThroughput:Math.random()*20+5,avgReadLatency:Math.random()*5+1,avgWriteLatency:Math.random()*8+2,cacheHitRatio:Math.random()*10+90,deadlocks:Math.floor(Math.random()*5),longRunningTransactions:Math.floor(Math.random()*10)},r=Array.from(this.queryMetrics.values()),n=r.sort((c,l)=>l.executionCount-c.executionCount).slice(0,10),i=r.filter((c)=>c.avgExecutionTime>1000).sort((c,l)=>l.avgExecutionTime-c.avgExecutionTime).slice(0,10),s=this.generateRecommendations(a,i),o={id:t,name:e.name,databaseIdentifier:e.databaseIdentifier,reportType:e.reportType,metrics:a,topQueries:n,slowQueries:i,recommendations:s,generatedAt:new Date};return this.reports.set(t,o),o}generateRecommendations(e,t){let a=[];if(e.avgCPU>70)a.push({type:"scaling",severity:"high",title:"High CPU Usage",description:`Average CPU usage is ${e.avgCPU.toFixed(1)}%, which is above the recommended threshold of 70%.`,impact:"Performance degradation, increased latency, potential timeouts",effort:"medium"});if(e.cacheHitRatio<95)a.push({type:"configuration",severity:"medium",title:"Low Cache Hit Ratio",description:`Cache hit ratio is ${e.cacheHitRatio.toFixed(1)}%. Consider increasing buffer pool size.`,impact:"Increased disk I/O, slower query performance",effort:"low"});if(e.deadlocks>0)a.push({type:"query",severity:"medium",title:"Deadlocks Detected",description:`${e.deadlocks} deadlock(s) detected. Review transaction isolation levels and query patterns.`,impact:"Transaction failures, application errors",effort:"high"});if(t.length>0)a.push({type:"index",severity:"high",title:"Slow Queries Detected",description:`${t.length} slow queries detected. Consider adding indexes or optimizing queries.`,impact:"High latency, poor user experience",effort:"medium"});if(e.avgReadLatency>10||e.avgWriteLatency>10)a.push({type:"scaling",severity:"high",title:"High I/O Latency",description:"Read or write latency is high. Consider upgrading to Provisioned IOPS or moving to a larger instance.",impact:"Slow query execution, application timeouts",effort:"medium"});return a}analyzeQuery(e){let t=`analysis-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,a=[{id:1,operation:"Seq Scan",table:"users",rows:1e4,cost:850.5,children:[]}],r=[];if(e.toLowerCase().includes("select *"))r.push({type:"full_table_scan",severity:"warning",description:"Query selects all columns. Consider selecting only required columns."});if(!e.toLowerCase().includes("where")&&e.toLowerCase().includes("select"))r.push({type:"full_table_scan",severity:"critical",description:"Query has no WHERE clause and may scan entire table."});return{id:t,queryId:t,sql:e,executionPlan:a,bottlenecks:r,recommendations:["Add appropriate indexes on WHERE clause columns","Consider using EXPLAIN ANALYZE to get actual execution statistics","Review and optimize JOIN conditions"],estimatedCost:a[0].cost}}recommendIndex(e){let t=`index-rec-${Date.now()}-${this.recommendationCounter++}`,a=`idx_${e.tableName}_${e.columns.join("_")}`,r={id:t,tableName:e.tableName,columns:e.columns,reason:e.reason,estimatedImprovement:e.estimatedImprovement||50,estimatedSize:e.columns.length*10,createSQL:`CREATE INDEX ${a} ON ${e.tableName} (${e.columns.join(", ")});`};return this.indexRecommendations.set(t,r),r}getInsights(e){return this.insights.get(e)}listInsights(){return Array.from(this.insights.values())}getSlowQueryLog(e){return this.slowQueryLogs.get(e)}listSlowQueryLogs(){return Array.from(this.slowQueryLogs.values())}getReport(e){return this.reports.get(e)}listReports(){return Array.from(this.reports.values())}listIndexRecommendations(){return Array.from(this.indexRecommendations.values())}generatePerformanceInsightsCF(e){return{EnablePerformanceInsights:e.enabled,PerformanceInsightsRetentionPeriod:e.retentionPeriod,...e.kmsKeyId&&{PerformanceInsightsKMSKeyId:e.kmsKeyId}}}generateSlowQueryAlarmCF(e){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:"Alert when slow queries exceed threshold",MetricName:"SlowQueryCount",Namespace:"AWS/RDS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",...e.snsTopicArn&&{AlarmActions:[e.snsTopicArn]}}}}clear(){this.insights.clear(),this.slowQueryLogs.clear(),this.queryMetrics.clear(),this.reports.clear(),this.indexRecommendations.clear(),this.insightsCounter=0,this.logCounter=0,this.metricCounter=0,this.reportCounter=0,this.recommendationCounter=0}}var mm=new Or;class Br{users=new Map;roles=new Map;audits=new Map;userCounter=0;roleCounter=0;auditCounter=0;createUser(e){let t=`db-user-${Date.now()}-${this.userCounter++}`,a={id:t,createdAt:new Date,...e};return this.users.set(t,a),a}createReadOnlyUser(e){let t=e.tables?e.tables.map((a)=>({database:e.database,table:a,privileges:["SELECT"]})):[{database:e.database,privileges:["SELECT"]}];return this.createUser({username:e.username,database:e.database,privileges:t,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:90})}createReadWriteUser(e){let t=e.tables?e.tables.map((a)=>({database:e.database,table:a,privileges:["SELECT","INSERT","UPDATE","DELETE"]})):[{database:e.database,privileges:["SELECT","INSERT","UPDATE","DELETE"]}];return this.createUser({username:e.username,database:e.database,privileges:t,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:60})}createAdminUser(e){return this.createUser({username:e.username,database:e.database,privileges:[{database:e.database,privileges:["ALL"]}],passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:30})}createApplicationUser(e){let t=e.tables.map((a)=>({database:e.database,table:a.name,privileges:a.privileges}));return this.createUser({username:e.username,database:e.database,privileges:t,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:90})}createRole(e){let t=`role-${Date.now()}-${this.roleCounter++}`,a={id:t,users:[],...e};return this.roles.set(t,a),a}assignUserToRole(e,t){let a=this.users.get(e),r=this.roles.get(t);if(!a)throw Error(`User not found: ${e}`);if(!r)throw Error(`Role not found: ${t}`);r.users.push(e);for(let n of r.privileges){let i=a.privileges.find((s)=>s.database===n.database&&s.table===n.table);if(i)i.privileges=Array.from(new Set([...i.privileges,...n.privileges]));else a.privileges.push({...n})}}grantPrivileges(e,t){let a=this.users.get(e);if(!a)return{success:!1,message:"User not found"};for(let r of t){let n=a.privileges.find((i)=>i.database===r.database&&i.table===r.table);if(n)n.privileges=Array.from(new Set([...n.privileges,...r.privileges]));else a.privileges.push(r)}return this.auditAccess({username:a.username,action:"GRANT",database:t[0]?.database,table:t[0]?.table,success:!0}),{success:!0,message:"Privileges granted successfully"}}revokePrivileges(e,t){let a=this.users.get(e);if(!a)return{success:!1,message:"User not found"};for(let r of t){let n=a.privileges.findIndex((i)=>i.database===r.database&&i.table===r.table);if(n!==-1){let i=a.privileges[n];if(i.privileges=i.privileges.filter((s)=>!r.privileges.includes(s)),i.privileges.length===0)a.privileges.splice(n,1)}}return this.auditAccess({username:a.username,action:"REVOKE",database:t[0]?.database,table:t[0]?.table,success:!0}),{success:!0,message:"Privileges revoked successfully"}}rotatePassword(e){let t=this.users.get(e);if(!t)return{success:!1};let a=`arn:aws:secretsmanager:us-east-1:123456789012:secret:db-${t.username}-${Date.now()}`;return t.passwordSecretArn=a,t.lastRotated=new Date,console.log(`Password rotated for user: ${t.username}`),{success:!0,newSecretArn:a}}needsPasswordRotation(e){let t=this.users.get(e);if(!t||!t.rotationEnabled||!t.lastRotated||!t.rotationDays)return!1;return(Date.now()-t.lastRotated.getTime())/86400000>=t.rotationDays}auditAccess(e){let t=`audit-${Date.now()}-${this.auditCounter++}`,a={id:t,timestamp:new Date,...e};return this.audits.set(t,a),a}getUserAccessHistory(e,t=100){return Array.from(this.audits.values()).filter((a)=>a.username===e).sort((a,r)=>r.timestamp.getTime()-a.timestamp.getTime()).slice(0,t)}getFailedLoginAttempts(e,t=24){let a=Date.now()-t*60*60*1000;return Array.from(this.audits.values()).filter((r)=>r.username===e&&r.action==="LOGIN"&&!r.success&&r.timestamp.getTime()>a)}generateCreateUserSQL(e,t="postgres"){let a=[];if(t==="postgres"){a.push(`CREATE USER ${e.username} WITH PASSWORD '${e.passwordSecretArn}';`);for(let r of e.privileges)if(r.privileges.includes("ALL"))a.push(`GRANT ALL PRIVILEGES ON DATABASE ${r.database} TO ${e.username};`);else{let n=r.privileges.join(", ");if(r.table)a.push(`GRANT ${n} ON ${r.database}.${r.table} TO ${e.username};`);else a.push(`GRANT ${n} ON DATABASE ${r.database} TO ${e.username};`)}}else{a.push(`CREATE USER '${e.username}'@'%' IDENTIFIED BY '${e.passwordSecretArn}';`);for(let r of e.privileges){let n=r.privileges.includes("ALL")?"ALL PRIVILEGES":r.privileges.join(", "),i=r.table?`${r.database}.${r.table}`:`${r.database}.*`;a.push(`GRANT ${n} ON ${i} TO '${e.username}'@'%';`)}a.push("FLUSH PRIVILEGES;")}return a.join(`
|
|
3761
|
+
`)}getUser(e){return this.users.get(e)}listUsers(){return Array.from(this.users.values())}getRole(e){return this.roles.get(e)}listRoles(){return Array.from(this.roles.values())}clear(){this.users.clear(),this.roles.clear(),this.audits.clear(),this.userCounter=0,this.roleCounter=0,this.auditCounter=0}}var pm=new Br;class _r{rotations=new Map;schedules=new Map;rotationCounter=0;scheduleCounter=0;createRotation(e){let t=`rotation-${Date.now()}-${this.rotationCounter++}`,a={id:t,...e};return this.rotations.set(t,a),a}enableRDSRotation(e){let t=this.createRotation({secretId:e.secretId,secretType:"rds_credentials",rotationEnabled:!0,rotationDays:e.rotationDays||30,rotationLambdaArn:this.generateRDSRotationLambdaArn(e.engine)});return t.nextRotation=new Date(Date.now()+t.rotationDays*24*60*60*1000),t}enableAPIKeyRotation(e){return this.createRotation({secretId:e.secretId,secretType:"api_key",rotationEnabled:!0,rotationDays:e.rotationDays||90,rotationLambdaArn:e.rotationLambdaArn})}enableOAuthRotation(e){return this.createRotation({secretId:e.secretId,secretType:"oauth_token",rotationEnabled:!0,rotationDays:e.rotationDays||60,rotationLambdaArn:e.rotationLambdaArn})}enableSSHKeyRotation(e){return this.createRotation({secretId:e.secretId,secretType:"ssh_key",rotationEnabled:!0,rotationDays:e.rotationDays||180,rotationLambdaArn:e.rotationLambdaArn})}createSchedule(e){let t=`schedule-${Date.now()}-${this.scheduleCounter++}`,a={id:t,...e};return this.schedules.set(t,a),a}async executeRotation(e){let t=this.rotations.get(e);if(!t)throw Error(`Rotation not found: ${e}`);console.log(`
|
|
3762
3762
|
Executing rotation for secret: ${t.secretId}`),console.log(`Secret type: ${t.secretType}`),console.log(`Rotation interval: ${t.rotationDays} days`);try{console.log(`
|
|
3763
3763
|
Rotation steps:`),console.log("1. Creating new secret version...");let a=`v${Date.now()}`;console.log("2. Testing new credentials..."),console.log("3. Updating application references..."),console.log("4. Marking previous version as deprecated...");let r=t.versionStages?.[0]||"v1";return console.log("5. Finalizing rotation..."),t.lastRotated=new Date,t.nextRotation=new Date(Date.now()+t.rotationDays*24*60*60*1000),console.log(`
|
|
3764
3764
|
✓ Rotation completed successfully`),console.log(` New version: ${a}`),console.log(` Next rotation: ${t.nextRotation.toISOString()}`),{success:!0,secretId:t.secretId,oldVersion:r,newVersion:a,rotatedAt:new Date}}catch(a){return console.error(`
|
|
3765
|
-
✗ Rotation failed:`,a),{success:!1,secretId:t.secretId,oldVersion:"unknown",newVersion:"unknown",rotatedAt:new Date,error:a instanceof Error?a.message:String(a)}}}needsRotation(e){let t=this.rotations.get(e);if(!t||!t.rotationEnabled)return!1;if(!t.lastRotated)return!0;return(Date.now()-t.lastRotated.getTime())/86400000>=t.rotationDays}getSecretsNeedingRotation(){return Array.from(this.rotations.values()).filter((e)=>this.needsRotation(e.id))}generateRDSRotationLambdaArn(e){let t={postgres:"SecretsManagerRDSPostgreSQLRotationSingleUser",mysql:"SecretsManagerRDSMySQLRotationSingleUser",sqlserver:"SecretsManagerRDSSQLServerRotationSingleUser",oracle:"SecretsManagerRDSOracleRotationSingleUser"};return`arn:aws:lambda:us-east-1:123456789012:function:${t[e]||t.postgres}`}getRotation(e){return this.rotations.get(e)}listRotations(){return Array.from(this.rotations.values())}getSchedule(e){return this.schedules.get(e)}listSchedules(){return Array.from(this.schedules.values())}generateRotationCF(e){return{RotationEnabled:e.rotationEnabled,RotationRules:{AutomaticallyAfterDays:e.rotationDays},...e.rotationLambdaArn&&{RotationLambdaARN:e.rotationLambdaArn}}}generateRotationLambdaCF(e){return{Type:"AWS::Lambda::Function",Properties:{FunctionName:e.functionName,Runtime:"python3.11",Handler:"lambda_function.lambda_handler",Role:{"Fn::GetAtt":["RotationLambdaRole","Arn"]},Timeout:30,Environment:{Variables:{SECRETS_MANAGER_ENDPOINT:"https://secretsmanager.us-east-1.amazonaws.com"}},...e.vpcConfig&&{VpcConfig:{SubnetIds:e.vpcConfig.subnetIds,SecurityGroupIds:e.vpcConfig.securityGroupIds}}}}}generateRotationLambdaRoleCF(){return{Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole","arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"],Policies:[{PolicyName:"SecretsRotationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:DescribeSecret","secretsmanager:GetSecretValue","secretsmanager:PutSecretValue","secretsmanager:UpdateSecretVersionStage"],Resource:"*"},{Effect:"Allow",Action:["secretsmanager:GetRandomPassword"],Resource:"*"}]}}]}}}generateRotationScheduleCF(e){return{Type:"AWS::Events::Rule",Properties:{Name:e.name,Description:`Rotation schedule for ${e.secrets.length} secrets`,ScheduleExpression:e.schedule,State:e.enabled?"ENABLED":"DISABLED",Targets:[{Arn:{"Fn::GetAtt":["RotationStateMachine","Arn"]},RoleArn:{"Fn::GetAtt":["EventBridgeRotationRole","Arn"]},Input:JSON.stringify({secrets:e.secrets})}]}}}clear(){this.rotations.clear(),this.schedules.clear(),this.rotationCounter=0,this.scheduleCounter=0}}var
|
|
3765
|
+
✗ Rotation failed:`,a),{success:!1,secretId:t.secretId,oldVersion:"unknown",newVersion:"unknown",rotatedAt:new Date,error:a instanceof Error?a.message:String(a)}}}needsRotation(e){let t=this.rotations.get(e);if(!t||!t.rotationEnabled)return!1;if(!t.lastRotated)return!0;return(Date.now()-t.lastRotated.getTime())/86400000>=t.rotationDays}getSecretsNeedingRotation(){return Array.from(this.rotations.values()).filter((e)=>this.needsRotation(e.id))}generateRDSRotationLambdaArn(e){let t={postgres:"SecretsManagerRDSPostgreSQLRotationSingleUser",mysql:"SecretsManagerRDSMySQLRotationSingleUser",sqlserver:"SecretsManagerRDSSQLServerRotationSingleUser",oracle:"SecretsManagerRDSOracleRotationSingleUser"};return`arn:aws:lambda:us-east-1:123456789012:function:${t[e]||t.postgres}`}getRotation(e){return this.rotations.get(e)}listRotations(){return Array.from(this.rotations.values())}getSchedule(e){return this.schedules.get(e)}listSchedules(){return Array.from(this.schedules.values())}generateRotationCF(e){return{RotationEnabled:e.rotationEnabled,RotationRules:{AutomaticallyAfterDays:e.rotationDays},...e.rotationLambdaArn&&{RotationLambdaARN:e.rotationLambdaArn}}}generateRotationLambdaCF(e){return{Type:"AWS::Lambda::Function",Properties:{FunctionName:e.functionName,Runtime:"python3.11",Handler:"lambda_function.lambda_handler",Role:{"Fn::GetAtt":["RotationLambdaRole","Arn"]},Timeout:30,Environment:{Variables:{SECRETS_MANAGER_ENDPOINT:"https://secretsmanager.us-east-1.amazonaws.com"}},...e.vpcConfig&&{VpcConfig:{SubnetIds:e.vpcConfig.subnetIds,SecurityGroupIds:e.vpcConfig.securityGroupIds}}}}}generateRotationLambdaRoleCF(){return{Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole","arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"],Policies:[{PolicyName:"SecretsRotationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:DescribeSecret","secretsmanager:GetSecretValue","secretsmanager:PutSecretValue","secretsmanager:UpdateSecretVersionStage"],Resource:"*"},{Effect:"Allow",Action:["secretsmanager:GetRandomPassword"],Resource:"*"}]}}]}}}generateRotationScheduleCF(e){return{Type:"AWS::Events::Rule",Properties:{Name:e.name,Description:`Rotation schedule for ${e.secrets.length} secrets`,ScheduleExpression:e.schedule,State:e.enabled?"ENABLED":"DISABLED",Targets:[{Arn:{"Fn::GetAtt":["RotationStateMachine","Arn"]},RoleArn:{"Fn::GetAtt":["EventBridgeRotationRole","Arn"]},Input:JSON.stringify({secrets:e.secrets})}]}}}clear(){this.rotations.clear(),this.schedules.clear(),this.rotationCounter=0,this.scheduleCounter=0}}var gm=new _r;class Wr{versions=new Map;audits=new Map;externalManagers=new Map;replications=new Map;policies=new Map;versionCounter=0;auditCounter=0;managerCounter=0;replicationCounter=0;policyCounter=0;createVersion(e){let t=`version-${Date.now()}-${this.versionCounter++}`,a={id:t,...e};return this.versions.set(t,a),this.auditAction({secretId:e.secretId,action:"CREATE",actor:"system",versionId:e.versionId,success:!0}),a}getVersionByStage(e,t){return Array.from(this.versions.values()).find((a)=>a.secretId===e&&a.versionStages.includes(t))}listVersions(e){return Array.from(this.versions.values()).filter((t)=>t.secretId===e).sort((t,a)=>a.createdAt.getTime()-t.createdAt.getTime())}deprecateVersion(e){let t=Array.from(this.versions.values()).find((a)=>a.versionId===e);if(t)t.deprecatedAt=new Date,t.versionStages=t.versionStages.filter((a)=>a!=="AWSCURRENT"),this.auditAction({secretId:t.secretId,action:"UPDATE",actor:"system",versionId:e,success:!0})}restoreVersion(e){let t=Array.from(this.versions.values()).find((a)=>a.versionId===e);if(t)Array.from(this.versions.values()).filter((a)=>a.secretId===t.secretId&&a.versionId!==e).forEach((a)=>{a.versionStages=a.versionStages.filter((r)=>r!=="AWSCURRENT")}),t.versionStages.push("AWSCURRENT"),t.deprecatedAt=void 0,this.auditAction({secretId:t.secretId,action:"RESTORE",actor:"system",versionId:e,success:!0})}auditAction(e){let t=`audit-${Date.now()}-${this.auditCounter++}`,a={id:t,timestamp:new Date,...e};return this.audits.set(t,a),a}getAuditTrail(e,t=100){return Array.from(this.audits.values()).filter((a)=>a.secretId===e).sort((a,r)=>r.timestamp.getTime()-a.timestamp.getTime()).slice(0,t)}getFailedAccesses(e,t=24){let a=Date.now()-t*60*60*1000;return Array.from(this.audits.values()).filter((r)=>r.secretId===e&&!r.success&&r.timestamp.getTime()>a)}registerExternalManager(e){let t=`ext-manager-${Date.now()}-${this.managerCounter++}`,a={id:t,...e};return this.externalManagers.set(t,a),a}registerVault(e){return this.registerExternalManager({type:"vault",name:e.name,endpoint:e.endpoint,authentication:{type:e.token?"token":"iam",credentials:e.token?{token:e.token}:void 0,roleArn:e.roleArn},syncEnabled:e.syncEnabled||!1,syncInterval:60})}registerOnePassword(e){return this.registerExternalManager({type:"onepassword",name:e.name,endpoint:e.endpoint||"https://my.1password.com",authentication:{type:"apikey",credentials:{apiKey:e.apiKey}},syncEnabled:e.syncEnabled||!1,syncInterval:30})}enableReplication(e){let t=`replication-${Date.now()}-${this.replicationCounter++}`,a={id:t,secretId:e.secretId,sourceRegion:e.sourceRegion,replicaRegions:e.replicaRegions,kmsKeyIds:e.kmsKeyIds,status:"replicating"};return this.replications.set(t,a),this.auditAction({secretId:e.secretId,action:"REPLICATE",actor:"system",success:!0}),setTimeout(()=>{a.status="completed"},100),a}createPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,secretId:e.secretId,policy:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:e.allowedPrincipals},Action:e.allowedActions,Resource:"*"}]}};return this.policies.set(t,a),a}createCrossAccountPolicy(e){let t=e.roleNames.map((a)=>`arn:aws:iam::${e.accountId}:role/${a}`);return this.createPolicy({secretId:e.secretId,allowedPrincipals:t,allowedActions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"]})}getVersion(e){return this.versions.get(e)}getExternalManager(e){return this.externalManagers.get(e)}listExternalManagers(){return Array.from(this.externalManagers.values())}getReplication(e){return this.replications.get(e)}listReplications(){return Array.from(this.replications.values())}generateSecretCF(e){return{Type:"AWS::SecretsManager::Secret",Properties:{Name:e.name,Description:e.description,...e.kmsKeyId&&{KmsKeyId:e.kmsKeyId},...e.replicaRegions&&{ReplicaRegions:e.replicaRegions.map((t)=>({Region:t}))}}}}generateSecretPolicyCF(e){return{Type:"AWS::SecretsManager::ResourcePolicy",Properties:{SecretId:e.secretId,ResourcePolicy:e.policy}}}clear(){this.versions.clear(),this.audits.clear(),this.externalManagers.clear(),this.replications.clear(),this.policies.clear(),this.versionCounter=0,this.auditCounter=0,this.managerCounter=0,this.replicationCounter=0,this.policyCounter=0}}var hm=new Wr;class Gr{certificates=new Map;renewals=new Map;validations=new Map;monitors=new Map;alerts=new Map;certificateCounter=0;renewalCounter=0;validationCounter=0;monitorCounter=0;alertCounter=0;requestCertificate(e){let t=`cert-${Date.now()}-${this.certificateCounter++}`,a=`arn:aws:acm:us-east-1:123456789012:certificate/${t}`,r={id:t,arn:a,domainName:e.domainName,subjectAlternativeNames:e.subjectAlternativeNames,validationMethod:e.validationMethod||"DNS",status:"PENDING_VALIDATION"};return this.certificates.set(t,r),this.createValidation(r),r}requestWildcardCertificate(e){let t=[];if(e.includeApex)t.push(e.domainName.replace("*.",""));return this.requestCertificate({domainName:e.domainName,subjectAlternativeNames:t.length>0?t:void 0,validationMethod:"DNS"})}requestMultiDomainCertificate(e){return this.requestCertificate({domainName:e.primaryDomain,subjectAlternativeNames:e.additionalDomains,validationMethod:e.validationMethod||"DNS"})}createValidation(e){let t={domainName:e.domainName,validationMethod:e.validationMethod,validationStatus:"PENDING"};if(e.validationMethod==="DNS")t.resourceRecords=[{name:`_${Math.random().toString(36).slice(2)}.${e.domainName}`,type:"CNAME",value:`_${Math.random().toString(36).slice(2)}.acm-validations.aws.`}];else t.validationEmails=[`admin@${e.domainName}`,`administrator@${e.domainName}`,`hostmaster@${e.domainName}`];return this.validations.set(e.id,t),t}validateCertificate(e){let t=this.certificates.get(e),a=this.validations.get(e);if(!t||!a)return{success:!1,message:"Certificate or validation not found"};return a.validationStatus="SUCCESS",t.status="ISSUED",t.issuedAt=new Date,t.expiresAt=new Date(Date.now()+31536000000),t.renewalEligibility=!0,t.issuer="Amazon",{success:!0,message:"Certificate validated and issued successfully"}}enableAutoRenewal(e){let t=`renewal-${Date.now()}-${this.renewalCounter++}`,a={id:t,certificateArn:e.certificateArn,autoRenew:!0,renewBeforeDays:e.renewBeforeDays||30};return this.renewals.set(t,a),a}async renewCertificate(e){let t=this.renewals.get(e);if(!t)return{success:!1,message:"Renewal configuration not found"};let a=Array.from(this.certificates.values()).find((r)=>r.arn===t.certificateArn);if(!a)return{success:!1,message:"Certificate not found"};console.log(`
|
|
3766
3766
|
Renewing certificate: ${a.domainName}`),console.log(`Certificate ARN: ${a.arn}`);try{return console.log(`
|
|
3767
3767
|
1. Requesting new certificate...`),console.log("2. Validating domain ownership..."),console.log("3. Issuing renewed certificate..."),console.log("4. Updating resource associations..."),a.issuedAt=new Date,a.expiresAt=new Date(Date.now()+31536000000),t.lastRenewal=new Date,t.renewalStatus="success",t.nextRenewal=new Date(a.expiresAt.getTime()-t.renewBeforeDays*24*60*60*1000),console.log(`
|
|
3768
|
-
✓ Certificate renewed successfully`),console.log(` New expiration: ${a.expiresAt.toISOString()}`),console.log(` Next renewal: ${t.nextRenewal.toISOString()}`),{success:!0,message:"Certificate renewed successfully"}}catch(r){return t.renewalStatus="failed",this.createAlert({certificateArn:a.arn,alertType:"renewal_failed",severity:"critical",message:`Certificate renewal failed: ${r}`}),{success:!1,message:r instanceof Error?r.message:String(r)}}}createMonitor(e){let t=`monitor-${Date.now()}-${this.monitorCounter++}`,a={id:t,...e};return this.monitors.set(t,a),a}checkExpiration(){let e=[],t=Date.now();for(let a of this.certificates.values()){if(!a.expiresAt)continue;let r=(a.expiresAt.getTime()-t)/86400000;if(r<0)e.push(this.createAlert({certificateArn:a.arn,alertType:"expired",severity:"critical",message:`Certificate has expired for ${a.domainName}`}));else if(r<30)e.push(this.createAlert({certificateArn:a.arn,alertType:"expiring_soon",severity:r<7?"critical":"warning",message:`Certificate expiring in ${Math.floor(r)} days for ${a.domainName}`}))}return e}createAlert(e){let t=`alert-${Date.now()}-${this.alertCounter++}`,a={id:t,timestamp:new Date,acknowledged:!1,...e};return this.alerts.set(t,a),a}acknowledgeAlert(e){let t=this.alerts.get(e);if(t)t.acknowledged=!0}getCertificate(e){return this.certificates.get(e)}listCertificates(){return Array.from(this.certificates.values())}getExpiringCertificates(e=30){let t=Date.now()+e*24*60*60*1000;return Array.from(this.certificates.values()).filter((a)=>a.expiresAt&&a.expiresAt.getTime()<t)}getValidation(e){return this.validations.get(e)}getRenewal(e){return this.renewals.get(e)}listRenewals(){return Array.from(this.renewals.values())}listAlerts(e=!1){return Array.from(this.alerts.values()).filter((t)=>t.acknowledged===e)}generateCertificateCF(e){return{Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:e.domainName,...e.subjectAlternativeNames&&{SubjectAlternativeNames:e.subjectAlternativeNames},ValidationMethod:e.validationMethod}}}generateExpirationAlarmCF(e){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`Certificate expiring in ${e.daysBeforeExpiration} days`,MetricName:"DaysToExpiry",Namespace:"AWS/CertificateManager",Statistic:"Minimum",Period:86400,EvaluationPeriods:1,Threshold:e.daysBeforeExpiration,ComparisonOperator:"LessThanThreshold",Dimensions:[{Name:"CertificateArn",Value:e.certificateArn}],...e.snsTopicArn&&{AlarmActions:[e.snsTopicArn]}}}}clear(){this.certificates.clear(),this.renewals.clear(),this.validations.clear(),this.monitors.clear(),this.alerts.clear(),this.certificateCounter=0,this.renewalCounter=0,this.validationCounter=0,this.monitorCounter=0,this.alertCounter=0}}var
|
|
3768
|
+
✓ Certificate renewed successfully`),console.log(` New expiration: ${a.expiresAt.toISOString()}`),console.log(` Next renewal: ${t.nextRenewal.toISOString()}`),{success:!0,message:"Certificate renewed successfully"}}catch(r){return t.renewalStatus="failed",this.createAlert({certificateArn:a.arn,alertType:"renewal_failed",severity:"critical",message:`Certificate renewal failed: ${r}`}),{success:!1,message:r instanceof Error?r.message:String(r)}}}createMonitor(e){let t=`monitor-${Date.now()}-${this.monitorCounter++}`,a={id:t,...e};return this.monitors.set(t,a),a}checkExpiration(){let e=[],t=Date.now();for(let a of this.certificates.values()){if(!a.expiresAt)continue;let r=(a.expiresAt.getTime()-t)/86400000;if(r<0)e.push(this.createAlert({certificateArn:a.arn,alertType:"expired",severity:"critical",message:`Certificate has expired for ${a.domainName}`}));else if(r<30)e.push(this.createAlert({certificateArn:a.arn,alertType:"expiring_soon",severity:r<7?"critical":"warning",message:`Certificate expiring in ${Math.floor(r)} days for ${a.domainName}`}))}return e}createAlert(e){let t=`alert-${Date.now()}-${this.alertCounter++}`,a={id:t,timestamp:new Date,acknowledged:!1,...e};return this.alerts.set(t,a),a}acknowledgeAlert(e){let t=this.alerts.get(e);if(t)t.acknowledged=!0}getCertificate(e){return this.certificates.get(e)}listCertificates(){return Array.from(this.certificates.values())}getExpiringCertificates(e=30){let t=Date.now()+e*24*60*60*1000;return Array.from(this.certificates.values()).filter((a)=>a.expiresAt&&a.expiresAt.getTime()<t)}getValidation(e){return this.validations.get(e)}getRenewal(e){return this.renewals.get(e)}listRenewals(){return Array.from(this.renewals.values())}listAlerts(e=!1){return Array.from(this.alerts.values()).filter((t)=>t.acknowledged===e)}generateCertificateCF(e){return{Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:e.domainName,...e.subjectAlternativeNames&&{SubjectAlternativeNames:e.subjectAlternativeNames},ValidationMethod:e.validationMethod}}}generateExpirationAlarmCF(e){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`Certificate expiring in ${e.daysBeforeExpiration} days`,MetricName:"DaysToExpiry",Namespace:"AWS/CertificateManager",Statistic:"Minimum",Period:86400,EvaluationPeriods:1,Threshold:e.daysBeforeExpiration,ComparisonOperator:"LessThanThreshold",Dimensions:[{Name:"CertificateArn",Value:e.certificateArn}],...e.snsTopicArn&&{AlarmActions:[e.snsTopicArn]}}}}clear(){this.certificates.clear(),this.renewals.clear(),this.validations.clear(),this.monitors.clear(),this.alerts.clear(),this.certificateCounter=0,this.renewalCounter=0,this.validationCounter=0,this.monitorCounter=0,this.alertCounter=0}}var ym=new Gr;class Fr{scans=new Map;findings=new Map;reports=new Map;complianceChecks=new Map;postures=new Map;scanCounter=0;findingCounter=0;reportCounter=0;checkCounter=0;postureCounter=0;createScan(e){let t=`scan-${Date.now()}-${this.scanCounter++}`,a={id:t,status:"queued",findings:[],...e};return this.scans.set(t,a),a}createContainerScan(e){return this.createScan({name:e.name,scanType:"container_image",target:{type:"ecr_image",identifier:e.imageUri,region:e.region||"us-east-1"}})}createLambdaScan(e){return this.createScan({name:e.name,scanType:"vulnerability",target:{type:"lambda",identifier:e.functionName,region:e.region||"us-east-1"}})}createSecretsDetectionScan(e){return this.createScan({name:e.name,scanType:"secrets_detection",target:{type:"repository",identifier:e.repositoryUrl}})}async executeScan(e){let t=this.scans.get(e);if(!t)throw Error(`Scan not found: ${e}`);console.log(`
|
|
3769
3769
|
Executing security scan: ${t.name}`),console.log(`Scan type: ${t.scanType}`),console.log(`Target: ${t.target.type} - ${t.target.identifier}`),t.status="running",t.startedAt=new Date;try{console.log(`
|
|
3770
3770
|
Scanning...`);let a=this.simulateFindings(t);return t.findings=a,t.status="completed",t.completedAt=new Date,t.summary={totalFindings:a.length,criticalCount:a.filter((r)=>r.severity==="CRITICAL").length,highCount:a.filter((r)=>r.severity==="HIGH").length,mediumCount:a.filter((r)=>r.severity==="MEDIUM").length,lowCount:a.filter((r)=>r.severity==="LOW").length,infoCount:a.filter((r)=>r.severity==="INFO").length,executionTime:t.completedAt.getTime()-t.startedAt.getTime()},console.log(`
|
|
3771
|
-
✓ Scan completed`),console.log(` Findings: ${t.summary.totalFindings}`),console.log(` Critical: ${t.summary.criticalCount}`),console.log(` High: ${t.summary.highCount}`),console.log(` Medium: ${t.summary.mediumCount}`),console.log(` Low: ${t.summary.lowCount}`),t}catch(a){throw t.status="failed",t.completedAt=new Date,a}}simulateFindings(e){let t=[],a=new Date;if(e.scanType==="container_image")t.push(this.createFinding({severity:"HIGH",title:"Vulnerable OpenSSL version detected",description:"OpenSSL 1.1.1k contains known vulnerabilities",cve:"CVE-2021-3711",cvss:7.5,affectedResource:e.target.identifier,remediation:"Update OpenSSL to version 1.1.1l or later",status:"OPEN",firstDetected:a,lastSeen:a})),t.push(this.createFinding({severity:"MEDIUM",title:"Outdated npm package: lodash",description:"lodash 4.17.19 has known security issues",cve:"CVE-2020-8203",cvss:5.3,affectedResource:e.target.identifier,remediation:"Update lodash to version 4.17.21 or later",status:"OPEN",firstDetected:a,lastSeen:a}));else if(e.scanType==="secrets_detection")t.push(this.createFinding({severity:"CRITICAL",title:"AWS Access Key exposed in code",description:"Hardcoded AWS access key found in source code",affectedResource:`${e.target.identifier}/src/config.ts:12`,remediation:"Remove hardcoded credentials and use AWS Secrets Manager",status:"OPEN",firstDetected:a,lastSeen:a}));return t}createFinding(e){let t=`finding-${Date.now()}-${this.findingCounter++}`,a={id:t,...e};return this.findings.set(t,a),a}suppressFinding(e,t){let a=this.findings.get(e);if(a){if(a.status="SUPPRESSED",console.log(`Finding suppressed: ${a.title}`),t)console.log(`Reason: ${t}`)}}resolveFinding(e){let t=this.findings.get(e);if(t)t.status="RESOLVED",console.log(`Finding resolved: ${t.title}`)}generateReport(e){let t=`report-${Date.now()}-${this.reportCounter++}`,a={id:t,scanId:e.scanId,reportType:e.reportType,format:e.format,generatedAt:new Date,s3Location:`s3://security-reports/${t}.${e.format}`};return this.reports.set(t,a),a}runComplianceCheck(e){let t=[];if(e.framework.includes("CIS"))t.push(this.createComplianceCheck({framework:e.framework,checkId:"1.1",title:"Avoid the use of root account",description:"Root account should not be used for everyday tasks",status:"PASS",severity:"CRITICAL",resourceType:e.resourceType,resourceId:e.resourceId})),t.push(this.createComplianceCheck({framework:e.framework,checkId:"2.1",title:"Ensure CloudTrail is enabled",description:"CloudTrail should be enabled in all regions",status:"FAIL",severity:"HIGH",resourceType:e.resourceType,resourceId:e.resourceId,remediation:"Enable CloudTrail in all regions"}));return t}createComplianceCheck(e){let t=`check-${Date.now()}-${this.checkCounter++}`,a={id:t,...e};return this.complianceChecks.set(t,a),a}assessSecurityPosture(e){let t=`posture-${Date.now()}-${this.postureCounter++}`,a=Array.from(this.complianceChecks.values()),r=a.filter((c)=>c.status==="PASS").length,n=a.length,i=n>0?Math.round(r/n*100):0,s;if(i>=90)s="A";else if(i>=80)s="B";else if(i>=70)s="C";else if(i>=60)s="D";else s="F";let o={id:t,accountId:e.accountId,region:e.region,score:i,grade:s,assessedAt:new Date,strengths:["IAM password policy enforced","Multi-factor authentication enabled","CloudTrail logging enabled"],weaknesses:["Some S3 buckets are publicly accessible","Security groups allow unrestricted ingress","Outdated dependencies in Lambda functions"],recommendations:["Review and update S3 bucket policies","Implement least-privilege security group rules","Update Lambda runtime versions and dependencies","Enable GuardDuty for threat detection"]};return this.postures.set(t,o),o}getScan(e){return this.scans.get(e)}listScans(){return Array.from(this.scans.values())}getOpenFindings(e){return Array.from(this.findings.values()).filter((t)=>t.status==="OPEN"&&(!e||t.severity===e))}getComplianceChecksByStatus(e){return Array.from(this.complianceChecks.values()).filter((t)=>t.status===e)}listPostures(){return Array.from(this.postures.values())}generateECRScanCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e,ImageScanningConfiguration:{ScanOnPush:!0},ImageTagMutability:"IMMUTABLE"}}}clear(){this.scans.clear(),this.findings.clear(),this.reports.clear(),this.complianceChecks.clear(),this.postures.clear(),this.scanCounter=0,this.findingCounter=0,this.reportCounter=0,this.checkCounter=0,this.postureCounter=0}}var
|
|
3771
|
+
✓ Scan completed`),console.log(` Findings: ${t.summary.totalFindings}`),console.log(` Critical: ${t.summary.criticalCount}`),console.log(` High: ${t.summary.highCount}`),console.log(` Medium: ${t.summary.mediumCount}`),console.log(` Low: ${t.summary.lowCount}`),t}catch(a){throw t.status="failed",t.completedAt=new Date,a}}simulateFindings(e){let t=[],a=new Date;if(e.scanType==="container_image")t.push(this.createFinding({severity:"HIGH",title:"Vulnerable OpenSSL version detected",description:"OpenSSL 1.1.1k contains known vulnerabilities",cve:"CVE-2021-3711",cvss:7.5,affectedResource:e.target.identifier,remediation:"Update OpenSSL to version 1.1.1l or later",status:"OPEN",firstDetected:a,lastSeen:a})),t.push(this.createFinding({severity:"MEDIUM",title:"Outdated npm package: lodash",description:"lodash 4.17.19 has known security issues",cve:"CVE-2020-8203",cvss:5.3,affectedResource:e.target.identifier,remediation:"Update lodash to version 4.17.21 or later",status:"OPEN",firstDetected:a,lastSeen:a}));else if(e.scanType==="secrets_detection")t.push(this.createFinding({severity:"CRITICAL",title:"AWS Access Key exposed in code",description:"Hardcoded AWS access key found in source code",affectedResource:`${e.target.identifier}/src/config.ts:12`,remediation:"Remove hardcoded credentials and use AWS Secrets Manager",status:"OPEN",firstDetected:a,lastSeen:a}));return t}createFinding(e){let t=`finding-${Date.now()}-${this.findingCounter++}`,a={id:t,...e};return this.findings.set(t,a),a}suppressFinding(e,t){let a=this.findings.get(e);if(a){if(a.status="SUPPRESSED",console.log(`Finding suppressed: ${a.title}`),t)console.log(`Reason: ${t}`)}}resolveFinding(e){let t=this.findings.get(e);if(t)t.status="RESOLVED",console.log(`Finding resolved: ${t.title}`)}generateReport(e){let t=`report-${Date.now()}-${this.reportCounter++}`,a={id:t,scanId:e.scanId,reportType:e.reportType,format:e.format,generatedAt:new Date,s3Location:`s3://security-reports/${t}.${e.format}`};return this.reports.set(t,a),a}runComplianceCheck(e){let t=[];if(e.framework.includes("CIS"))t.push(this.createComplianceCheck({framework:e.framework,checkId:"1.1",title:"Avoid the use of root account",description:"Root account should not be used for everyday tasks",status:"PASS",severity:"CRITICAL",resourceType:e.resourceType,resourceId:e.resourceId})),t.push(this.createComplianceCheck({framework:e.framework,checkId:"2.1",title:"Ensure CloudTrail is enabled",description:"CloudTrail should be enabled in all regions",status:"FAIL",severity:"HIGH",resourceType:e.resourceType,resourceId:e.resourceId,remediation:"Enable CloudTrail in all regions"}));return t}createComplianceCheck(e){let t=`check-${Date.now()}-${this.checkCounter++}`,a={id:t,...e};return this.complianceChecks.set(t,a),a}assessSecurityPosture(e){let t=`posture-${Date.now()}-${this.postureCounter++}`,a=Array.from(this.complianceChecks.values()),r=a.filter((c)=>c.status==="PASS").length,n=a.length,i=n>0?Math.round(r/n*100):0,s;if(i>=90)s="A";else if(i>=80)s="B";else if(i>=70)s="C";else if(i>=60)s="D";else s="F";let o={id:t,accountId:e.accountId,region:e.region,score:i,grade:s,assessedAt:new Date,strengths:["IAM password policy enforced","Multi-factor authentication enabled","CloudTrail logging enabled"],weaknesses:["Some S3 buckets are publicly accessible","Security groups allow unrestricted ingress","Outdated dependencies in Lambda functions"],recommendations:["Review and update S3 bucket policies","Implement least-privilege security group rules","Update Lambda runtime versions and dependencies","Enable GuardDuty for threat detection"]};return this.postures.set(t,o),o}getScan(e){return this.scans.get(e)}listScans(){return Array.from(this.scans.values())}getOpenFindings(e){return Array.from(this.findings.values()).filter((t)=>t.status==="OPEN"&&(!e||t.severity===e))}getComplianceChecksByStatus(e){return Array.from(this.complianceChecks.values()).filter((t)=>t.status===e)}listPostures(){return Array.from(this.postures.values())}generateECRScanCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e,ImageScanningConfiguration:{ScanOnPush:!0},ImageTagMutability:"IMMUTABLE"}}}clear(){this.scans.clear(),this.findings.clear(),this.reports.clear(),this.complianceChecks.clear(),this.postures.clear(),this.scanCounter=0,this.findingCounter=0,this.reportCounter=0,this.checkCounter=0,this.postureCounter=0}}var fm=new Fr;class Vr{configs=new Map;results=new Map;policies=new Map;configCounter=0;resultCounter=0;policyCounter=0;configureScan(e){let t=`scan-config-${Date.now()}-${this.configCounter++}`,a={id:t,...e};return this.configs.set(t,a),a}configureTrivyScan(e){return this.configureScan({repository:e.repository,imageTag:e.imageTag,scanner:"trivy",scanOnPush:e.scanOnPush??!0,ignoreUnfixed:e.ignoreUnfixed??!1,failOnSeverity:"HIGH"})}configureSnykScan(e){return this.configureScan({repository:e.repository,imageTag:e.imageTag,scanner:"snyk",scanOnPush:e.scanOnPush??!0,failOnSeverity:"HIGH"})}configureECRScan(e){return this.configureScan({repository:e.repository,imageTag:"latest",scanner:"ecr",scanOnPush:e.scanOnPush??!0,failOnSeverity:"CRITICAL"})}async scanImage(e){let t=this.configs.get(e);if(!t)throw Error(`Scan config not found: ${e}`);let a=`${t.repository}:${t.imageTag}`;console.log(`
|
|
3772
3772
|
Scanning image: ${a}`),console.log(`Scanner: ${t.scanner}`);let r=`scan-result-${Date.now()}-${this.resultCounter++}`,n=this.simulateVulnerabilities(t),i={total:n.length,critical:n.filter((c)=>c.severity==="CRITICAL").length,high:n.filter((c)=>c.severity==="HIGH").length,medium:n.filter((c)=>c.severity==="MEDIUM").length,low:n.filter((c)=>c.severity==="LOW").length,unknown:n.filter((c)=>c.severity==="UNKNOWN").length},s=this.evaluateScanResult(t,i),o={id:r,imageUri:a,scannerType:t.scanner,scanDate:new Date,vulnerabilities:n,summary:i,passed:s};return this.results.set(r,o),console.log(`
|
|
3773
|
-
Scan Results:`),console.log(` Total vulnerabilities: ${i.total}`),console.log(` Critical: ${i.critical}`),console.log(` High: ${i.high}`),console.log(` Medium: ${i.medium}`),console.log(` Low: ${i.low}`),console.log(` Status: ${s?"✓ PASSED":"✗ FAILED"}`),o}simulateVulnerabilities(e){let t=[];if(e.scanner==="trivy"||e.scanner==="ecr")t.push({id:"vuln-1",cve:"CVE-2024-1234",severity:"HIGH",packageName:"openssl",installedVersion:"1.1.1k",fixedVersion:"1.1.1l",title:"OpenSSL buffer overflow",description:"Buffer overflow vulnerability in OpenSSL",references:["https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-1234"],cvss:7.5}),t.push({id:"vuln-2",cve:"CVE-2024-5678",severity:"MEDIUM",packageName:"curl",installedVersion:"7.68.0",fixedVersion:"7.79.0",title:"curl remote code execution",description:"Remote code execution in curl",references:["https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-5678"],cvss:5.3});return t}evaluateScanResult(e,t){if(!e.failOnSeverity)return!0;switch(e.failOnSeverity){case"CRITICAL":return t.critical===0;case"HIGH":return t.critical===0&&t.high===0;case"MEDIUM":return t.critical===0&&t.high===0&&t.medium===0;case"LOW":return t.total===0;default:return!0}}createPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,...e};return this.policies.set(t,a),a}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
|
|
3773
|
+
Scan Results:`),console.log(` Total vulnerabilities: ${i.total}`),console.log(` Critical: ${i.critical}`),console.log(` High: ${i.high}`),console.log(` Medium: ${i.medium}`),console.log(` Low: ${i.low}`),console.log(` Status: ${s?"✓ PASSED":"✗ FAILED"}`),o}simulateVulnerabilities(e){let t=[];if(e.scanner==="trivy"||e.scanner==="ecr")t.push({id:"vuln-1",cve:"CVE-2024-1234",severity:"HIGH",packageName:"openssl",installedVersion:"1.1.1k",fixedVersion:"1.1.1l",title:"OpenSSL buffer overflow",description:"Buffer overflow vulnerability in OpenSSL",references:["https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-1234"],cvss:7.5}),t.push({id:"vuln-2",cve:"CVE-2024-5678",severity:"MEDIUM",packageName:"curl",installedVersion:"7.68.0",fixedVersion:"7.79.0",title:"curl remote code execution",description:"Remote code execution in curl",references:["https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-5678"],cvss:5.3});return t}evaluateScanResult(e,t){if(!e.failOnSeverity)return!0;switch(e.failOnSeverity){case"CRITICAL":return t.critical===0;case"HIGH":return t.critical===0&&t.high===0;case"MEDIUM":return t.critical===0&&t.high===0&&t.medium===0;case"LOW":return t.total===0;default:return!0}}createPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,...e};return this.policies.set(t,a),a}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 Sm=new Vr;class Ur{configs=new Map;multiStageConfigs=new Map;optimizations=new Map;analyses=new Map;configCounter=0;multiStageCounter=0;optimizationCounter=0;analysisCounter=0;createBuildConfig(e){let t=`build-config-${Date.now()}-${this.configCounter++}`,a={id:t,...e};return this.configs.set(t,a),a}createOptimizedBuildConfig(e){let t={type:e.enableCache?"registry":"inline",cacheFrom:e.registry?[`${e.registry}/cache`]:void 0,cacheTo:e.registry?`${e.registry}/cache`:void 0,maxCacheAge:7};return this.createBuildConfig({name:e.name,dockerfile:e.dockerfile,context:".",cacheStrategy:t,buildArgs:{BUILDKIT_INLINE_CACHE:"1"}})}createMultiStageConfig(e){let t=`multi-stage-${Date.now()}-${this.multiStageCounter++}`,a={id:t,...e};return this.multiStageConfigs.set(t,a),a}createNodeMultiStageBuild(e){let t=e.nodeVersion||"18-alpine";return this.createMultiStageConfig({name:e.name,targetStage:e.targetStage||"production",stages:[{name:"dependencies",baseImage:`node:${t}`,workdir:"/app",commands:["COPY package*.json ./","RUN npm ci --only=production"]},{name:"build",baseImage:`node:${t}`,workdir:"/app",commands:["COPY package*.json ./","RUN npm ci","COPY . .","RUN npm run build"]},{name:"production",baseImage:`node:${t}`,workdir:"/app",copyFrom:["dependencies:/app/node_modules","build:/app/dist"],commands:["COPY package*.json ./","ENV NODE_ENV=production",'CMD ["node", "dist/index.js"]']}]})}generateDockerfile(e){let t=this.multiStageConfigs.get(e);if(!t)throw Error(`Multi-stage config not found: ${e}`);let a=[];for(let r of t.stages){if(a.push(`# Stage: ${r.name}`),a.push(`FROM ${r.baseImage} AS ${r.name}`),r.workdir)a.push(`WORKDIR ${r.workdir}`);if(r.env)for(let[n,i]of Object.entries(r.env))a.push(`ENV ${n}=${i}`);for(let n of r.commands)a.push(n);a.push("")}return a.join(`
|
|
3774
3774
|
`)}analyzeImage(e,t){let a=`analysis-${Date.now()}-${this.analysisCounter++}`,r=t.map((o)=>({...o,cacheable:this.isLayerCacheable(o.command)})),n=r.reduce((o,c)=>o+c.size,0),i=r.filter((o)=>!o.cacheable&&o.size>100).length,s={id:a,imageId:e,layers:r,totalSize:n,unnecessaryLayers:i};return this.analyses.set(a,s),s}isLayerCacheable(e){let t=["FROM","RUN","COPY","ADD","WORKDIR","ENV"],a=["CMD","ENTRYPOINT","LABEL"];for(let r of t)if(e.startsWith(r))return!0;for(let r of a)if(e.startsWith(r))return!1;return!1}generateOptimizations(e){let t=this.analyses.get(e);if(!t)throw Error(`Analysis not found: ${e}`);let a=`optimization-${Date.now()}-${this.optimizationCounter++}`,r=[],n=t.layers.filter((l)=>l.command.startsWith("RUN"));if(n.length>5)r.push({type:"layer_reduction",priority:"high",title:"Combine RUN commands",description:`${n.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 i=t.layers[0];if(i.command.includes("ubuntu")||i.command.includes("debian"))r.push({type:"base_image",priority:"medium",title:"Use Alpine base image",description:"Switch to Alpine Linux for smaller image size",example:"FROM node:18-alpine",impact:"Reduce image size by 50-70%"});let s=t.layers.filter((l)=>l.command.startsWith("COPY"));if(s.length>0&&s[0].index>3)r.push({type:"cache_optimization",priority:"high",title:"Copy dependencies first",description:"Copy package files before source code to leverage layer caching",example:`COPY package*.json ./
|
|
3775
3775
|
RUN npm install
|
|
3776
|
-
COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let o={sizeBefore:t.totalSize,sizeAfter:t.totalSize*0.6,timeBefore:300,timeAfter:120},c={id:a,name:`Optimization for ${t.imageId}`,recommendations:r,estimatedSavings:o};return this.optimizations.set(a,c),c}getBuildConfig(e){return this.configs.get(e)}listBuildConfigs(){return Array.from(this.configs.values())}getMultiStageConfig(e){return this.multiStageConfigs.get(e)}listMultiStageConfigs(){return Array.from(this.multiStageConfigs.values())}getOptimization(e){return this.optimizations.get(e)}listOptimizations(){return Array.from(this.optimizations.values())}clear(){this.configs.clear(),this.multiStageConfigs.clear(),this.optimizations.clear(),this.analyses.clear(),this.configCounter=0,this.multiStageCounter=0,this.optimizationCounter=0,this.analysisCounter=0}}var Sm=new Fr;class jr{registries=new Map;credentials=new Map;registryCounter=0;credentialsCounter=0;createRegistry(e){let t=`registry-${Date.now()}-${this.registryCounter++}`,a={id:t,...e};return this.registries.set(t,a),a}createECRRepository(e){return this.createRegistry({name:e.name,registryType:"ecr",repositoryUri:`123456789012.dkr.ecr.${e.region||"us-east-1"}.amazonaws.com/${e.name}`,region:e.region||"us-east-1",encryption:{encryptionType:e.encryption||"AES256",kmsKeyId:e.kmsKeyId},scanning:{scanOnPush:e.scanOnPush??!0}})}createManagedRepository(e){let t=this.createECRRepository({name:e.name,region:e.region,scanOnPush:!0,encryption:"KMS"});return t.lifecycle={id:`lifecycle-${Date.now()}`,rules:[{rulePriority:1,description:"Keep only last N images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount||10},action:{type:"expire"}},{rulePriority:2,description:"Remove images older than N days",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays||30,countUnit:"days"},action:{type:"expire"}}]},t}enableReplication(e,t){let a=this.registries.get(e);if(!a)throw Error(`Registry not found: ${e}`);return a.replication={enabled:!0,destinations:t},a}createCredentials(e){let t=`creds-${Date.now()}-${this.credentialsCounter++}`,a={id:t,...e};return this.credentials.set(t,a),a}getRegistry(e){return this.registries.get(e)}listRegistries(){return Array.from(this.registries.values())}generateECRRepositoryCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e.name,ImageScanningConfiguration:{ScanOnPush:e.scanning?.scanOnPush??!1},EncryptionConfiguration:{EncryptionType:e.encryption?.encryptionType||"AES256",...e.encryption?.kmsKeyId&&{KmsKey:e.encryption.kmsKeyId}},ImageTagMutability:"MUTABLE",...e.lifecycle&&{LifecyclePolicy:{LifecyclePolicyText:JSON.stringify({rules:e.lifecycle.rules})}}}}}generateReplicationConfigCF(e){return{Type:"AWS::ECR::ReplicationConfiguration",Properties:{ReplicationConfiguration:{Rules:e.destinations.map((t)=>({Destinations:[{Region:t.region,...t.registryId&&{RegistryId:t.registryId}}]}))}}}}clear(){this.registries.clear(),this.credentials.clear(),this.registryCounter=0,this.credentialsCounter=0}}var bm=new jr;class Kr{meshes=new Map;virtualNodes=new Map;virtualRouters=new Map;virtualGateways=new Map;meshCounter=0;nodeCounter=0;routerCounter=0;gatewayCounter=0;createMesh(e){let t=`mesh-${Date.now()}-${this.meshCounter++}`,a={id:t,...e};return this.meshes.set(t,a),a}createAppMesh(e){return this.createMesh({name:e.name,meshType:"app_mesh",services:e.services,virtualNodes:[],virtualRouters:[],virtualGateways:[]})}createVirtualNode(e){let t=`vnode-${Date.now()}-${this.nodeCounter++}`,a={id:t,...e};return this.virtualNodes.set(t,a),a}createHTTPVirtualNode(e){return this.createVirtualNode({name:e.name,serviceName:e.serviceName,listeners:[{port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3},timeout:{perRequest:15000,idle:300000}}],serviceDiscovery:{type:"aws_cloud_map",namespace:e.namespace,serviceName:e.serviceName}})}createVirtualRouter(e){let t=`vrouter-${Date.now()}-${this.routerCounter++}`,a={id:t,...e};return this.virtualRouters.set(t,a),a}createCanaryRoute(e){return this.createVirtualRouter({name:e.name,listeners:[{port:e.port,protocol:e.protocol}],routes:[{name:"canary-route",match:{prefix:"/"},action:{weightedTargets:[{virtualNode:e.stableTarget,weight:100-e.canaryWeight},{virtualNode:e.canaryTarget,weight:e.canaryWeight}]},retryPolicy:{maxRetries:3,perRetryTimeout:5000,httpRetryEvents:["server-error","gateway-error"],tcpRetryEvents:["connection-error"]}}]})}createVirtualGateway(e){let t=`vgateway-${Date.now()}-${this.gatewayCounter++}`,a={id:t,...e};return this.virtualGateways.set(t,a),a}createIngressGateway(e){let t={port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3}};if(e.enableTLS&&e.certificateArn)t.tls={mode:"STRICT",certificate:{acm:e.certificateArn}};return this.createVirtualGateway({name:e.name,listeners:[t],logging:{accessLog:{file:{path:"/dev/stdout"}}}})}getMesh(e){return this.meshes.get(e)}listMeshes(){return Array.from(this.meshes.values())}getVirtualNode(e){return this.virtualNodes.get(e)}listVirtualNodes(){return Array.from(this.virtualNodes.values())}generateMeshCF(e){return{Type:"AWS::AppMesh::Mesh",Properties:{MeshName:e.name,Spec:{EgressFilter:{Type:"ALLOW_ALL"}}}}}generateVirtualNodeCF(e,t){return{Type:"AWS::AppMesh::VirtualNode",Properties:{MeshName:t,VirtualNodeName:e.name,Spec:{Listeners:e.listeners.map((a)=>({PortMapping:{Port:a.port,Protocol:a.protocol},...a.healthCheck&&{HealthCheck:{Protocol:a.healthCheck.protocol,...a.healthCheck.path&&{Path:a.healthCheck.path},IntervalMillis:a.healthCheck.interval*1000,TimeoutMillis:a.healthCheck.timeout*1000,HealthyThreshold:a.healthCheck.healthyThreshold,UnhealthyThreshold:a.healthCheck.unhealthyThreshold}}})),ServiceDiscovery:{AWSCloudMap:{NamespaceName:e.serviceDiscovery.namespace,ServiceName:e.serviceDiscovery.serviceName}}}}}}generateVirtualRouterCF(e,t){return{Type:"AWS::AppMesh::VirtualRouter",Properties:{MeshName:t,VirtualRouterName:e.name,Spec:{Listeners:e.listeners.map((a)=>({PortMapping:{Port:a.port,Protocol:a.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 Am=new Kr;class Hr{layers=new Map;versions=new Map;permissions=new Map;layerCounter=0;versionCounter=0;permissionCounter=0;createLayer(e){let t=`layer-${Date.now()}-${this.layerCounter++}`,a=1,r={id:t,layerArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:1`,version:1,...e};return this.layers.set(t,r),r}createNodeDependenciesLayer(e){return this.createLayer({layerName:e.layerName,description:"Node.js dependencies layer",compatibleRuntimes:[`nodejs${e.nodeVersion}`],content:{type:"s3",s3Bucket:e.s3Bucket,s3Key:e.s3Key},size:5242880})}createUtilitiesLayer(e){return this.createLayer({layerName:e.layerName,description:"Shared utilities and helpers",compatibleRuntimes:e.runtimes,content:{type:"s3",s3Bucket:e.s3Bucket,s3Key:e.s3Key},size:1048576})}publishVersion(e){let t=this.layers.get(e);if(!t)throw Error(`Layer not found: ${e}`);let a=`version-${Date.now()}-${this.versionCounter++}`,r=t.version+1,n={id:a,layerName:t.layerName,version:r,createdAt:new Date,compatibleRuntimes:t.compatibleRuntimes,size:t.size,codeHash:this.generateHash()};return this.versions.set(a,n),t.version=r,t.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${t.layerName}:${r}`,n}addPermission(e){let t=`permission-${Date.now()}-${this.permissionCounter++}`,a={id:t,layerName:e.layerName,version:e.version,principal:e.principal,action:"lambda:GetLayerVersion",organizationId:e.organizationId};return this.permissions.set(t,a),a}generateHash(){return Math.random().toString(36).substring(2,15)}getLayer(e){return this.layers.get(e)}listLayers(){return Array.from(this.layers.values())}getLayerVersions(e){return Array.from(this.versions.values()).filter((t)=>t.layerName===e)}generateLayerCF(e){return{Type:"AWS::Lambda::LayerVersion",Properties:{LayerName:e.layerName,Description:e.description,Content:e.content.type==="s3"?{S3Bucket:e.content.s3Bucket,S3Key:e.content.s3Key,...e.content.s3ObjectVersion&&{S3ObjectVersion:e.content.s3ObjectVersion}}:{ZipFile:e.content.zipFile},CompatibleRuntimes:e.compatibleRuntimes,...e.licenseInfo&&{LicenseInfo:e.licenseInfo}}}}generateLayerPermissionCF(e){return{Type:"AWS::Lambda::LayerVersionPermission",Properties:{LayerVersionArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:${e.version}`,Action:e.action,Principal:e.principal,...e.organizationId&&{OrganizationId:e.organizationId}}}}clear(){this.layers.clear(),this.versions.clear(),this.permissions.clear(),this.layerCounter=0,this.versionCounter=0,this.permissionCounter=0}}var Cm=new Hr;class qr{versions=new Map;aliases=new Map;deployments=new Map;versionCounter=0;aliasCounter=0;deploymentCounter=0;publishVersion(e){let t=`version-${Date.now()}-${this.versionCounter++}`,a=this.getNextVersionNumber(e.functionName),r={id:t,functionName:e.functionName,version:a.toString(),functionArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${a}`,codeHash:this.generateHash(),description:e.description,runtime:e.runtime,memorySize:e.memorySize,timeout:e.timeout,publishedAt:new Date};return this.versions.set(t,r),r}getNextVersionNumber(e){let t=Array.from(this.versions.values()).filter((a)=>a.functionName===e).map((a)=>parseInt(a.version));return t.length>0?Math.max(...t)+1:1}createAlias(e){let t=`alias-${Date.now()}-${this.aliasCounter++}`,a={id:t,aliasArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${e.aliasName}`,revisionId:this.generateHash(),...e};return this.aliases.set(t,a),a}createProductionAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"production",functionVersion:e.version,description:"Production alias"})}createStagingAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"staging",functionVersion:e.version,description:"Staging alias"})}updateAlias(e,t){let a=this.aliases.get(e);if(!a)throw Error(`Alias not found: ${e}`);return a.functionVersion=t,a.revisionId=this.generateHash(),a}configureWeightedRouting(e,t){let a=this.aliases.get(e);if(!a)throw Error(`Alias not found: ${e}`);return a.routingConfig={additionalVersionWeights:t},a}createCanaryDeployment(e){let t=`deployment-${Date.now()}-${this.deploymentCounter++}`,a=Array.from(this.aliases.values()).find((n)=>n.functionName===e.functionName&&n.aliasName===e.aliasName);if(!a)a=this.createAlias({functionName:e.functionName,aliasName:e.aliasName,functionVersion:e.fromVersion});this.configureWeightedRouting(a.id,{[e.toVersion]:e.canaryWeight});let r={id:t,functionName:e.functionName,fromVersion:e.fromVersion,toVersion:e.toVersion,aliasName:e.aliasName,strategy:"canary",status:"in_progress",startedAt:new Date};return this.deployments.set(t,r),r}completeDeployment(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);let a=Array.from(this.aliases.values()).find((r)=>r.functionName===t.functionName&&r.aliasName===t.aliasName);if(a)a.functionVersion=t.toVersion,a.routingConfig=void 0;return t.status="completed",t.completedAt=new Date,t}rollbackDeployment(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);let a=Array.from(this.aliases.values()).find((r)=>r.functionName===t.functionName&&r.aliasName===t.aliasName);if(a)a.functionVersion=t.fromVersion,a.routingConfig=void 0;return t.status="failed",t.completedAt=new Date,t}generateHash(){return Math.random().toString(36).substring(2,15)}getVersion(e){return this.versions.get(e)}listVersions(e){let t=Array.from(this.versions.values());return e?t.filter((a)=>a.functionName===e):t}getAlias(e){return this.aliases.get(e)}listAliases(e){let t=Array.from(this.aliases.values());return e?t.filter((a)=>a.functionName===e):t}generateVersionCF(e){return{Type:"AWS::Lambda::Version",Properties:{FunctionName:e.functionName,Description:e.description}}}generateAliasCF(e){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.functionName,Name:e.aliasName,FunctionVersion:e.functionVersion,Description:e.description,...e.routingConfig&&{RoutingConfig:{AdditionalVersionWeights:Object.entries(e.routingConfig.additionalVersionWeights||{}).map(([t,a])=>({FunctionVersion:t,FunctionWeight:a}))}}}}}clear(){this.versions.clear(),this.aliases.clear(),this.deployments.clear(),this.versionCounter=0,this.aliasCounter=0,this.deploymentCounter=0}}var Tm=new qr;class zr{configs=new Map;provisionedConfigs=new Map;schedules=new Map;autoScalingConfigs=new Map;configCounter=0;provisionedCounter=0;scheduleCounter=0;autoScalingCounter=0;setReservedConcurrency(e){let t=`concurrency-${Date.now()}-${this.configCounter++}`,a={id:t,functionName:e.functionName,reservedConcurrency:e.reservedConcurrency};return this.configs.set(t,a),a}setProvisionedConcurrency(e){let t=`provisioned-${Date.now()}-${this.provisionedCounter++}`,a={id:t,functionName:e.functionName,qualifier:e.qualifier,provisionedConcurrentExecutions:e.provisionedConcurrentExecutions,status:"pending",lastModified:new Date};return this.provisionedConfigs.set(t,a),setTimeout(()=>{a.status="ready",a.allocatedConcurrency=e.provisionedConcurrentExecutions,a.availableConcurrency=e.provisionedConcurrentExecutions},100),a}configureWarmPool(e){return this.setProvisionedConcurrency({functionName:e.functionName,qualifier:e.alias,provisionedConcurrentExecutions:e.minInstances})}createSchedule(e){let t=`schedule-${Date.now()}-${this.scheduleCounter++}`,a={id:t,...e};return this.schedules.set(t,a),a}createBusinessHoursSchedule(e){return this.createSchedule({name:`${e.functionName}-business-hours`,functionName:e.functionName,qualifier:e.qualifier,schedule:[{name:"business-hours",cronExpression:"0 8 * * MON-FRI",targetConcurrency:e.businessHoursConcurrency},{name:"off-hours",cronExpression:"0 18 * * MON-FRI",targetConcurrency:e.offHoursConcurrency},{name:"weekend",cronExpression:"0 0 * * SAT",targetConcurrency:e.offHoursConcurrency}]})}configureAutoScaling(e){let t=`autoscaling-${Date.now()}-${this.autoScalingCounter++}`,a={id:t,...e};return this.autoScalingConfigs.set(t,a),a}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 vm=new zr;class Jr{destinations=new Map;records=new Map;eventBridgeDestinations=new Map;destinationCounter=0;recordCounter=0;eventBridgeCounter=0;configureDestinations(e){let t=`destination-${Date.now()}-${this.destinationCounter++}`,a={id:t,...e};return this.destinations.set(t,a),a}configureSQSDestination(e){let t={type:"sqs",arn:e.queueArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureSNSDestination(e){let t={type:"sns",arn:e.topicArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureEventBridgeDestination(e){let t={type:"eventbridge",arn:e.eventBusArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureLambdaDestination(e){let t={type:"lambda",arn:e.destinationFunctionArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureDLQWithNotification(e){return this.configureDestinations({functionName:e.functionName,failureDestination:{type:"sqs",arn:e.dlqArn},maxEventAge:3600,maxRetries:0})}createEventBridgeIntegration(e){let t=`eventbridge-${Date.now()}-${this.eventBridgeCounter++}`,a={id:t,functionName:e.functionName,eventBusArn:e.eventBusArn,detailType:e.detailType||"Lambda Function Invocation Result",source:e.source||`lambda.${e.functionName}`};return this.eventBridgeDestinations.set(t,a),a}sendToDestination(e){let t=Array.from(this.destinations.values()).find((i)=>i.functionName===e.functionName);if(!t)return null;let a=e.status==="success"?t.successDestination:t.failureDestination;if(!a)return null;let r=`record-${Date.now()}-${this.recordCounter++}`,n={id:r,timestamp:new Date,functionName:e.functionName,requestId:e.requestId,status:e.status,destinationType:a.type,destinationArn:a.arn,payload:e.payload,error:e.error};return this.records.set(r,n),n}getDestination(e){return this.destinations.get(e)}listDestinations(e){let t=Array.from(this.destinations.values());return e?t.filter((a)=>a.functionName===e):t}getDestinationRecords(e){let t=Array.from(this.records.values());return e?t.filter((a)=>a.functionName===e):t}generateEventInvokeConfigCF(e){return{Type:"AWS::Lambda::EventInvokeConfig",Properties:{FunctionName:e.functionName,Qualifier:e.qualifier||"$LATEST",MaximumEventAgeInSeconds:e.maxEventAge||21600,MaximumRetryAttempts:e.maxRetries??2,...e.successDestination&&{DestinationConfig:{OnSuccess:{Destination:e.successDestination.arn}}},...e.failureDestination&&{DestinationConfig:{OnFailure:{Destination:e.failureDestination.arn}}}}}}generateEventBridgeRuleCF(e){return{Type:"AWS::Events::Rule",Properties:{EventBusName:e.eventBusArn.split("/").pop(),EventPattern:{source:[e.source],"detail-type":[e.detailType]},State:"ENABLED",Targets:[{Arn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}`,Id:e.id}]}}}clear(){this.destinations.clear(),this.records.clear(),this.eventBridgeDestinations.clear(),this.destinationCounter=0,this.recordCounter=0,this.eventBridgeCounter=0}}var wm=new Jr;class Qr{vpcConfigs=new Map;endpoints=new Map;networkInterfaces=new Map;connectivity=new Map;configCounter=0;endpointCounter=0;eniCounter=0;connectivityCounter=0;configureVPC(e){let t=`vpc-config-${Date.now()}-${this.configCounter++}`,a={id:t,...e};this.vpcConfigs.set(t,a);for(let r of e.subnetIds)this.createNetworkInterface({functionName:e.functionName,subnetId:r});return a}configurePrivateVPC(e){return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.privateSubnetIds,securityGroupIds:[e.securityGroupId],ipv6Allowed:!1})}configureMultiAZVPC(e){if(e.subnetIds.length<2)throw Error("Multi-AZ configuration requires at least 2 subnets");return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds})}createVPCEndpoint(e){let t=`endpoint-${Date.now()}-${this.endpointCounter++}`,a={id:t,...e};return this.endpoints.set(t,a),a}createS3Endpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.s3",endpointType:"Gateway",privateDnsEnabled:!1})}createDynamoDBEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.dynamodb",endpointType:"Gateway",privateDnsEnabled:!1})}createSecretsManagerEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.secretsmanager",endpointType:"Interface",subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds,privateDnsEnabled:!0})}createNetworkInterface(e){let t=`eni-${Date.now()}-${this.eniCounter++}`,a={id:t,functionName:e.functionName,networkInterfaceId:`eni-${Math.random().toString(36).substring(2,15)}`,subnetId:e.subnetId,privateIpAddress:`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`,status:"creating",attachedAt:new Date};return this.networkInterfaces.set(t,a),setTimeout(()=>{a.status="available"},100),a}analyzeConnectivity(e){let t=`connectivity-${Date.now()}-${this.connectivityCounter++}`,a=Array.from(this.vpcConfigs.values()).find((c)=>c.functionName===e.functionName),r=Array.from(this.endpoints.values()).filter((c)=>c.vpcId===a?.vpcId).map((c)=>c.serviceName),n=[],i=e.hasNATGateway??!1,s=e.hasInternetGateway??!1;if(!i&&!s)n.push("Add NAT Gateway for internet access");if(!r.includes("com.amazonaws.us-east-1.s3"))n.push("Add S3 VPC endpoint to reduce NAT costs");if(!r.includes("com.amazonaws.us-east-1.dynamodb"))n.push("Add DynamoDB VPC endpoint for private access");let o={id:t,functionName:e.functionName,hasInternetAccess:i||s,hasNATGateway:i,hasVPCEndpoints:r.length>0,endpoints:r,recommendations:n};return this.connectivity.set(t,o),o}getVPCConfig(e){return this.vpcConfigs.get(e)}listVPCConfigs(e){let t=Array.from(this.vpcConfigs.values());return e?t.filter((a)=>a.functionName===e):t}getNetworkInterfaces(e){return Array.from(this.networkInterfaces.values()).filter((t)=>t.functionName===e)}listVPCEndpoints(e){let t=Array.from(this.endpoints.values());return e?t.filter((a)=>a.vpcId===e):t}generateVPCConfigCF(e){return{VpcConfig:{SubnetIds:e.subnetIds,SecurityGroupIds:e.securityGroupIds,...e.ipv6Allowed&&{Ipv6AllowedForDualStack:!0}}}}generateVPCEndpointCF(e){return{Type:"AWS::EC2::VPCEndpoint",Properties:{VpcId:e.vpcId,ServiceName:e.serviceName,VpcEndpointType:e.endpointType,...e.subnetIds&&{SubnetIds:e.subnetIds},...e.securityGroupIds&&{SecurityGroupIds:e.securityGroupIds},...e.privateDnsEnabled!==void 0&&{PrivateDnsEnabled:e.privateDnsEnabled}}}}generateSecurityGroupCF(e){return{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:e.groupName,GroupDescription:`Security group for Lambda ${e.groupName}`,VpcId:e.vpcId,...e.ingressRules&&{SecurityGroupIngress:e.ingressRules.map((t)=>({IpProtocol:t.protocol,FromPort:t.fromPort,ToPort:t.toPort,...t.cidrIp&&{CidrIp:t.cidrIp},...t.sourceSecurityGroupId&&{SourceSecurityGroupId:t.sourceSecurityGroupId}}))},...e.egressRules&&{SecurityGroupEgress:e.egressRules.map((t)=>({IpProtocol:t.protocol,FromPort:t.fromPort,ToPort:t.toPort,CidrIp:t.cidrIp||"0.0.0.0/0"}))}}}}clear(){this.vpcConfigs.clear(),this.endpoints.clear(),this.networkInterfaces.clear(),this.connectivity.clear(),this.configCounter=0,this.endpointCounter=0,this.eniCounter=0,this.connectivityCounter=0}}var Em=new Qr;class $r{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(e){let t=`dlq-${Date.now()}-${this.configCounter++}`,a={id:t,...e};return this.dlqConfigs.set(t,a),a}configureSQSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.queueArn,targetType:"sqs",maxReceiveCount:e.maxReceiveCount||3,retentionPeriod:e.retentionPeriod||1209600})}configureSNSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.topicArn,targetType:"sns"})}configureDLQWithAlarm(e){let t=this.configureSQSDLQ({functionName:e.functionName,queueArn:e.queueArn});return this.createDLQAlarm({dlqConfigId:t.id,alarmName:`${e.functionName}-dlq-alarm`,threshold:e.alarmThreshold,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0}),t}sendToDLQ(e){let t=`message-${Date.now()}-${this.messageCounter++}`,a={id:t,timestamp:new Date,...e};return this.messages.set(t,a),a}createDLQAlarm(e){let t=`alarm-${Date.now()}-${this.alarmCounter++}`,a={id:t,...e};return this.alarms.set(t,a),a}createAgeAlarm(e){let t=this.dlqConfigs.get(e.dlqConfigId);if(!t)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:e.dlqConfigId,alarmName:`${t.functionName}-dlq-age-alarm`,threshold:e.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0})}async reprocessMessage(e){let t=this.messages.get(e);if(!t)throw Error(`Message not found: ${e}`);let a=Array.from(this.dlqConfigs.values()).find((i)=>i.functionName===t.functionName);if(!a)throw Error(`DLQ config not found for function: ${t.functionName}`);let r=`reprocess-${Date.now()}-${this.reprocessCounter++}`,n={id:r,dlqConfigId:a.id,messageId:e,status:"pending",startedAt:new Date};return this.reprocessing.set(r,n),setTimeout(()=>{n.status="processing",setTimeout(()=>{let i=Math.random()>0.3;if(n.status=i?"success":"failed",n.completedAt=new Date,!i)n.error="Reprocessing failed - same error occurred";else this.messages.delete(e)},100)},50),n}async batchReprocess(e){let t=this.dlqConfigs.get(e.dlqConfigId);if(!t)throw Error(`DLQ config not found: ${e.dlqConfigId}`);let a=Array.from(this.messages.values()).filter((r)=>r.functionName===t.functionName).slice(0,e.maxMessages||10).map((r)=>this.reprocessMessage(r.id));return Promise.all(a)}getDLQStats(e){let t=this.dlqConfigs.get(e);if(!t)throw Error(`DLQ config not found: ${e}`);let a=Array.from(this.messages.values()).filter((s)=>s.functionName===t.functionName),r={},n=0;for(let s of a)r[s.errorType]=(r[s.errorType]||0)+1,n+=s.attemptCount;let i=a.map((s)=>s.timestamp);return{totalMessages:a.length,oldestMessage:i.length>0?new Date(Math.min(...i.map((s)=>s.getTime()))):void 0,newestMessage:i.length>0?new Date(Math.max(...i.map((s)=>s.getTime()))):void 0,averageAttempts:a.length>0?n/a.length:0,errorTypes:r}}getDLQConfig(e){return this.dlqConfigs.get(e)}listDLQConfigs(){return Array.from(this.dlqConfigs.values())}getDLQMessages(e){let t=this.dlqConfigs.get(e);if(!t)return[];return Array.from(this.messages.values()).filter((a)=>a.functionName===t.functionName)}generateDLQCF(e){return{DeadLetterConfig:{TargetArn:e.targetArn}}}generateSQSDLQCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:`${e.functionName}-dlq`,MessageRetentionPeriod:e.retentionPeriod||1209600,...e.maxReceiveCount&&{RedrivePolicy:{deadLetterTargetArn:e.targetArn,maxReceiveCount:e.maxReceiveCount}}}}}generateDLQAlarmCF(e){let t=this.dlqConfigs.get(e.dlqConfigId);if(!t)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`DLQ alarm for ${t.functionName}`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:e.evaluationPeriods,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:t.targetArn.split(":").pop()}],...e.notificationTopicArn&&{AlarmActions:[e.notificationTopicArn]}}}}clear(){this.dlqConfigs.clear(),this.messages.clear(),this.alarms.clear(),this.reprocessing.clear(),this.configCounter=0,this.messageCounter=0,this.alarmCounter=0,this.reprocessCounter=0}}var Pm=new $r;class Yr{policies=new Map;healthChecks=new Map;trafficPolicies=new Map;policyCounter=0;healthCheckCounter=0;trafficPolicyCounter=0;createWeightedPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,type:"weighted",...e};return this.policies.set(t,a),a}createLatencyPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,type:"latency",...e};return this.policies.set(t,a),a}createFailoverPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,type:"failover",...e};return this.policies.set(t,a),a}createGeolocationPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,type:"geolocation",...e};return this.policies.set(t,a),a}createGeoproximityPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,type:"geoproximity",...e};return this.policies.set(t,a),a}createHTTPHealthCheck(e){let t=`health-check-${Date.now()}-${this.healthCheckCounter++}`,a={id:t,type:e.port===443?"https":"http",requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",port:e.port||(e.port===443?443:80),...e};return this.healthChecks.set(t,a),setTimeout(()=>{a.healthCheckStatus=Math.random()>0.2?"Healthy":"Unhealthy"},100),a}createTCPHealthCheck(e){let t=`health-check-${Date.now()}-${this.healthCheckCounter++}`,a={id:t,type:"tcp",fullyQualifiedDomainName:e.ipAddress,requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(t,a),setTimeout(()=>{a.healthCheckStatus=Math.random()>0.1?"Healthy":"Unhealthy"},100),a}createCalculatedHealthCheck(e){let t=`health-check-${Date.now()}-${this.healthCheckCounter++}`,a={id:t,type:"calculated",requestInterval:30,failureThreshold:0,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(t,a),setTimeout(()=>{let r=e.childHealthChecks.filter((n)=>{return this.healthChecks.get(n)?.healthCheckStatus==="Healthy"}).length;a.healthCheckStatus=r>=e.healthThreshold?"Healthy":"Unhealthy"},150),a}createTrafficPolicy(e){let t=`traffic-policy-${Date.now()}-${this.trafficPolicyCounter++}`,a={id:t,version:1,...e};return this.trafficPolicies.set(t,a),a}createFailoverTrafficPolicy(e){return this.createTrafficPolicy({name:e.name,document:{recordType:e.recordType||"A",startRule:"failover",endpoints:{primary:{type:"value",value:e.primaryEndpoint},secondary:{type:"value",value:e.secondaryEndpoint}},rules:{failover:{ruleType:"failover",primary:"primary",secondary:"secondary"}}}})}createGeoproximityTrafficPolicy(e){let t={},a=[];return e.locations.forEach((r,n)=>{let i=`endpoint${n}`;t[i]={type:"value",value:r.endpoint},a.push({endpointReference:i,region:r.region,latitude:r.latitude,longitude:r.longitude,bias:r.bias})}),this.createTrafficPolicy({name:e.name,document:{recordType:"A",startRule:"geoproximity",endpoints:t,rules:{geoproximity:{ruleType:"geoproximity",locations:a}}}})}getPolicy(e){return this.policies.get(e)}listPolicies(){return Array.from(this.policies.values())}getHealthCheck(e){return this.healthChecks.get(e)}listHealthChecks(){return Array.from(this.healthChecks.values())}getHealthCheckStatus(e){return this.healthChecks.get(e)?.healthCheckStatus||"Unknown"}generateHealthCheckCF(e){let t={Type:"AWS::Route53::HealthCheck",Properties:{HealthCheckConfig:{Type:e.type.toUpperCase(),RequestInterval:e.requestInterval,FailureThreshold:e.failureThreshold,...e.measureLatency&&{MeasureLatency:!0}},HealthCheckTags:[{Key:"Name",Value:e.name}]}};if(e.type==="calculated"){let a=e;t.Properties.HealthCheckConfig.ChildHealthChecks=a.childHealthChecks,t.Properties.HealthCheckConfig.HealthThreshold=a.healthThreshold}else{if(e.ipAddress)t.Properties.HealthCheckConfig.IPAddress=e.ipAddress;if(e.fullyQualifiedDomainName)t.Properties.HealthCheckConfig.FullyQualifiedDomainName=e.fullyQualifiedDomainName;if(e.port)t.Properties.HealthCheckConfig.Port=e.port;if(e.resourcePath)t.Properties.HealthCheckConfig.ResourcePath=e.resourcePath;if(e.enableSNI)t.Properties.HealthCheckConfig.EnableSNI=!0}return t}generateWeightedRecordSetCF(e){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.hostedZoneId,Name:e.name,Type:e.type,TTL:e.ttl,ResourceRecords:e.resourceRecords,Weight:e.weight,SetIdentifier:e.setIdentifier,...e.healthCheckId&&{HealthCheckId:e.healthCheckId}}}}generateFailoverRecordSetCF(e){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.hostedZoneId,Name:e.name,Type:e.type,TTL:e.ttl,ResourceRecords:e.resourceRecords,Failover:e.failover,SetIdentifier:e.setIdentifier,...e.healthCheckId&&{HealthCheckId:e.healthCheckId}}}}clear(){this.policies.clear(),this.healthChecks.clear(),this.trafficPolicies.clear(),this.policyCounter=0,this.healthCheckCounter=0,this.trafficPolicyCounter=0}}var Im=new Yr;class Xr{configs=new Map;ksks=new Map;validations=new Map;configCounter=0;kskCounter=0;validationCounter=0;enableDNSSEC(e){let t=`dnssec-${Date.now()}-${this.configCounter++}`,a={id:t,hostedZoneId:e.hostedZoneId,status:"SIGNING",signingStatus:"Initializing DNSSEC signing"};if(this.configs.set(t,a),e.kmsKeyArn)this.createKSK({name:`ksk-${e.hostedZoneId}`,hostedZoneId:e.hostedZoneId,kmsKeyArn:e.kmsKeyArn});return setTimeout(()=>{a.status="SIGNED",a.signingStatus="DNSSEC signing complete"},100),a}disableDNSSEC(e){let t=this.configs.get(e);if(!t)throw Error(`DNSSEC config not found: ${e}`);return t.status="DELETING",t.signingStatus="Removing DNSSEC signing",setTimeout(()=>{t.status="NOT_SIGNING",t.signingStatus="DNSSEC signing removed"},100),t}createKSK(e){let t=`ksk-${Date.now()}-${this.kskCounter++}`,a={id:t,status:"ACTIVE",flag:257,keyManagementServiceArn:e.kmsKeyArn,digestAlgorithm:2,keyTag:Math.floor(Math.random()*65535),publicKey:this.generatePublicKey(),...e};a.dnskeyRecord=`${a.flag} 3 8 ${a.publicKey}`;let r=this.generateDigest(a.dnskeyRecord);return a.digestValue=r,a.dsRecord=`${a.keyTag} 8 ${a.digestAlgorithm} ${r}`,this.ksks.set(t,a),a}deactivateKSK(e){let t=this.ksks.get(e);if(!t)throw Error(`KSK not found: ${e}`);return t.status="INACTIVE",t}validateDNSSEC(e){let t=`validation-${Date.now()}-${this.validationCounter++}`,a=e.checkDNSKEY!==!1?Math.random()>0.1:!1,r=e.checkRRSIG!==!1?Math.random()>0.1:!1,n=a&&r,i=[];if(!a)i.push("DNSKEY record not found");if(!r)i.push("RRSIG record not found");let s;if(!a&&!r)s="INSECURE";else if(a&&r&&n)s="VALID";else if(a||r)s="BOGUS",i.push("Invalid signature or incomplete DNSSEC chain");else s="INVALID";let o={id:t,domain:e.domain,validationStatus:s,dnskeyPresent:a,rrsigPresent:r,validSignature:n,errors:i};return this.validations.set(t,o),o}getDNSSECConfig(e){return this.configs.get(e)}listDNSSECConfigs(){return Array.from(this.configs.values())}getKSK(e){return this.ksks.get(e)}listKSKs(e){let t=Array.from(this.ksks.values());return e?t.filter((a)=>a.hostedZoneId===e):t}getDSRecord(e){let t=this.ksks.get(e);if(!t||!t.dsRecord)throw Error("DS record not available");return t.dsRecord}generatePublicKey(){let e="";for(let t=0;t<256;t++)e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return e}generateDigest(e){let t="";for(let a=0;a<64;a++)t+="0123456789ABCDEF".charAt(Math.floor(Math.random()*16));return t}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 Rm=new Xr;class Zr{endpoints=new Map;rules=new Map;firewalls=new Map;ruleGroups=new Map;domainLists=new Map;endpointCounter=0;ruleCounter=0;firewallCounter=0;ruleGroupCounter=0;domainListCounter=0;createResolverEndpoint(e){let t=`endpoint-${Date.now()}-${this.endpointCounter++}`,a={id:t,status:"CREATING",...e};return this.endpoints.set(t,a),setTimeout(()=>{a.status="OPERATIONAL",a.ipAddresses.forEach((r)=>{if(!r.ip)r.ip=`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`})},100),a}createInboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"INBOUND",ipAddresses:e.subnetIds.map((t)=>({subnetId:t})),securityGroupIds:e.securityGroupIds})}createOutboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"OUTBOUND",ipAddresses:e.subnetIds.map((t)=>({subnetId:t})),securityGroupIds:e.securityGroupIds})}createResolverRule(e){let t=`rule-${Date.now()}-${this.ruleCounter++}`,a={id:t,status:"CREATING",...e};return this.rules.set(t,a),setTimeout(()=>{a.status="COMPLETE"},100),a}createForwardRule(e){return this.createResolverRule({name:e.name,ruleType:"FORWARD",domainName:e.domainName,targetIps:e.targetIps,resolverEndpointId:e.resolverEndpointId})}createSystemRule(e){return this.createResolverRule({name:e.name,ruleType:"SYSTEM",domainName:e.domainName})}createFirewallDomainList(e){let t=`domain-list-${Date.now()}-${this.domainListCounter++}`,a={id:t,status:"CREATING",...e};return this.domainLists.set(t,a),setTimeout(()=>{a.status="COMPLETE"},100),a}createFirewallRuleGroup(e){let t=`rule-group-${Date.now()}-${this.ruleGroupCounter++}`,a={id:t,name:e.name,rules:e.rules.map((r,n)=>({id:`rule-${t}-${n}`,...r})),shareStatus:"NOT_SHARED"};return this.ruleGroups.set(t,a),a}createBlockRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"BLOCK",blockResponse:e.blockResponse||"NODATA",blockOverrideDomain:e.blockOverrideDomain,firewallDomainListId:e.domainListId}]})}createAllowRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"ALLOW",firewallDomainListId:e.domainListId}]})}createDNSFirewall(e){let t=`firewall-${Date.now()}-${this.firewallCounter++}`,a={id:t,name:e.name,firewallRuleGroupAssociations:e.ruleGroupAssociations.map((r,n)=>({id:`assoc-${t}-${n}`,vpcId:e.vpcId,firewallRuleGroupId:r.firewallRuleGroupId,priority:r.priority,mutationProtection:r.mutationProtection||"DISABLED",status:"COMPLETE"}))};return this.firewalls.set(t,a),a}createMalwareProtectionFirewall(e){let t=this.createFirewallDomainList({name:`${e.name}-malware-domains`,domains:e.maliciousDomains}),a=this.createBlockRule({name:`${e.name}-block-malware`,priority:100,domainListId:t.id,blockResponse:"NXDOMAIN"});return this.createDNSFirewall({name:e.name,vpcId:e.vpcId,ruleGroupAssociations:[{firewallRuleGroupId:a.id,priority:100,mutationProtection:"ENABLED"}]})}getEndpoint(e){return this.endpoints.get(e)}listEndpoints(e){let t=Array.from(this.endpoints.values());return e?t.filter((a)=>a.direction===e):t}getRule(e){return this.rules.get(e)}listRules(){return Array.from(this.rules.values())}getFirewall(e){return this.firewalls.get(e)}listFirewalls(){return Array.from(this.firewalls.values())}generateResolverEndpointCF(e){return{Type:"AWS::Route53Resolver::ResolverEndpoint",Properties:{Name:e.name,Direction:e.direction,IpAddresses:e.ipAddresses.map((t)=>({SubnetId:t.subnetId,...t.ip&&{Ip:t.ip}})),SecurityGroupIds:e.securityGroupIds}}}generateResolverRuleCF(e){return{Type:"AWS::Route53Resolver::ResolverRule",Properties:{Name:e.name,RuleType:e.ruleType,DomainName:e.domainName,...e.targetIps&&{TargetIps:e.targetIps.map((t)=>({Ip:t.ip,Port:t.port||53}))},...e.resolverEndpointId&&{ResolverEndpointId:e.resolverEndpointId}}}}generateFirewallRuleGroupCF(e){return{Type:"AWS::Route53Resolver::FirewallRuleGroup",Properties:{Name:e.name,FirewallRules:e.rules.map((t)=>({Name:t.name,Priority:t.priority,Action:t.action,FirewallDomainListId:t.firewallDomainListId,...t.blockResponse&&{BlockResponse:t.blockResponse},...t.blockOverrideDomain&&{BlockOverrideDomain:t.blockOverrideDomain},...t.blockOverrideTTL&&{BlockOverrideTtl:t.blockOverrideTTL}}))}}}clear(){this.endpoints.clear(),this.rules.clear(),this.firewalls.clear(),this.ruleGroups.clear(),this.domainLists.clear(),this.endpointCounter=0,this.ruleCounter=0,this.firewallCounter=0,this.ruleGroupCounter=0,this.domainListCounter=0}}var Nm=new Zr;class en{bounces=new Map;complaints=new Map;handlers=new Map;suppressionList=new Map;metrics=new Map;bounceCounter=0;complaintCounter=0;handlerCounter=0;suppressionCounter=0;metricsCounter=0;recordBounce(e){let t=`bounce-${Date.now()}-${this.bounceCounter++}`,a={id:t,...e};if(this.bounces.set(t,a),e.bounceType==="Permanent")this.addToSuppressionList({emailAddress:e.recipient,reason:"BOUNCE"});return a}recordComplaint(e){let t=`complaint-${Date.now()}-${this.complaintCounter++}`,a={id:t,...e};this.complaints.set(t,a);for(let r of e.recipients)this.addToSuppressionList({emailAddress:r,reason:"COMPLAINT"});return a}createBounceHandler(e){let t=`handler-${Date.now()}-${this.handlerCounter++}`,a={id:t,...e};return this.handlers.set(t,a),a}createAutomaticBounceHandler(e){return this.createBounceHandler({name:e.name,bounceThreshold:5,complaintThreshold:0.1,suppressionDuration:2592000,autoSuppress:!0,notificationTopicArn:e.notificationTopicArn})}addToSuppressionList(e){let t=`suppression-${Date.now()}-${this.suppressionCounter++}`,a=e.expirationDays?new Date(Date.now()+e.expirationDays*24*60*60*1000):void 0,r={id:t,emailAddress:e.emailAddress,reason:e.reason,suppressedAt:new Date,expiresAt:a,bounceCount:e.reason==="BOUNCE"?1:0,complaintCount:e.reason==="COMPLAINT"?1:0};return this.suppressionList.set(e.emailAddress,r),r}removeFromSuppressionList(e){return this.suppressionList.delete(e)}isSuppressed(e){let t=this.suppressionList.get(e);if(!t)return!1;if(t.expiresAt&&t.expiresAt<new Date)return this.suppressionList.delete(e),!1;return!0}getBounceStatistics(e,t){let a=Array.from(this.bounces.values()).filter((u)=>u.timestamp>=e&&u.timestamp<=t),r=a.length,n=a.filter((u)=>u.bounceType==="Permanent").length,i=a.filter((u)=>u.bounceType==="Transient").length,s=r*10,o=r/s*100,c=new Map;for(let u of a)c.set(u.recipient,(c.get(u.recipient)||0)+1);let l=Array.from(c.entries()).map(([u,m])=>({email:u,count:m})).sort((u,m)=>m.count-u.count).slice(0,10);return{totalBounces:r,permanentBounces:n,transientBounces:i,bounceRate:o,topRecipients:l}}getComplaintStatistics(e,t){let a=Array.from(this.complaints.values()).filter((c)=>c.timestamp>=e&&c.timestamp<=t),r=a.length,n=new Set;for(let c of a)for(let l of c.recipients)n.add(l);let i=n.size,s=r*1000,o=r/s*100;return{totalComplaints:r,uniqueComplainters:i,complaintRate:o}}calculateReputationMetrics(){let e=`metrics-${Date.now()}-${this.metricsCounter++}`,t=new Date,a=new Date(t.getTime()-86400000),r=this.getBounceStatistics(a,t),n=this.getComplaintStatistics(a,t),i;if(r.bounceRate>10||n.complaintRate>0.5)i="Shutdown";else if(r.bounceRate>5||n.complaintRate>0.1)i="Probation";else if(r.bounceRate>2||n.complaintRate>0.05)i="Warning";else i="Good";let s={id:e,timestamp:t,bounceRate:r.bounceRate,complaintRate:n.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:r.totalBounces*10,reputationStatus:i};return this.metrics.set(e,s),s}getBounces(e){let t=Array.from(this.bounces.values());return e?t.filter((a)=>a.messageId===e):t}getComplaints(e){let t=Array.from(this.complaints.values());return e?t.filter((a)=>a.messageId===e):t}listSuppressionList(e){let t=Array.from(this.suppressionList.values());return e?t.filter((a)=>a.reason===e):t}generateSNSSubscriptionCF(e){return{Type:"AWS::SNS::Subscription",Properties:{TopicArn:e.topicArn,Endpoint:e.endpoint,Protocol:e.protocol}}}generateEventDestinationCF(e){return{Type:"AWS::SES::ConfigurationSetEventDestination",Properties:{ConfigurationSetName:e.configurationSetName,EventDestination:{Name:e.eventDestinationName,Enabled:!0,MatchingEventTypes:e.eventTypes,...e.snsTopicArn&&{SnsDestination:{TopicARN:e.snsTopicArn}},...e.cloudWatchDestination&&{CloudWatchDestination:e.cloudWatchDestination}}}}}clear(){this.bounces.clear(),this.complaints.clear(),this.handlers.clear(),this.suppressionList.clear(),this.metrics.clear(),this.bounceCounter=0,this.complaintCounter=0,this.handlerCounter=0,this.suppressionCounter=0,this.metricsCounter=0}}var Dm=new en;class tn{events=new Map;campaigns=new Map;reports=new Map;abTests=new Map;eventCounter=0;campaignCounter=0;reportCounter=0;abTestCounter=0;trackEvent(e){let t=`event-${Date.now()}-${this.eventCounter++}`,a={id:t,...e};if(this.events.set(t,a),e.tags?.campaignId)this.updateCampaignStats(e.tags.campaignId,e.eventType);return a}trackOpen(e){return this.trackEvent({...e,eventType:"open",timestamp:new Date})}trackClick(e){return this.trackEvent({...e,eventType:"click",timestamp:new Date})}createCampaign(e){let t=`campaign-${Date.now()}-${this.campaignCounter++}`,a={id:t,sentCount:0,deliveredCount:0,openCount:0,clickCount:0,bounceCount:0,complaintCount:0,createdAt:new Date,...e};return this.campaigns.set(t,a),a}updateCampaignStats(e,t){let a=this.campaigns.get(e);if(!a)return;switch(t){case"send":a.sentCount++;break;case"delivery":a.deliveredCount++;break;case"open":a.openCount++;break;case"click":a.clickCount++;break;case"bounce":a.bounceCount++;break;case"complaint":a.complaintCount++;break}}generateReport(e){let t=`report-${Date.now()}-${this.reportCounter++}`,a=Array.from(this.events.values()).filter((S)=>{let E=S.timestamp>=e.startDate&&S.timestamp<=e.endDate,v=!e.campaignId||S.tags?.campaignId===e.campaignId;return E&&v}),r=a.filter((S)=>S.eventType==="send").length,n=a.filter((S)=>S.eventType==="delivery").length,i=a.filter((S)=>S.eventType==="open").length,s=a.filter((S)=>S.eventType==="click").length,o=a.filter((S)=>S.eventType==="bounce").length,c=a.filter((S)=>S.eventType==="complaint").length,l=r>0?n/r*100:0,u=n>0?i/n*100:0,m=n>0?s/n*100:0,p=i>0?s/i*100:0,g=r>0?o/r*100:0,h=n>0?c/n*100:0,y=new Map;for(let S of a)if(S.eventType==="click"){let E=S;y.set(E.link,(y.get(E.link)||0)+1)}let b=Array.from(y.entries()).map(([S,E])=>({link:S,clicks:E})).sort((S,E)=>E.clicks-S.clicks).slice(0,10),T={desktop:0,mobile:0,tablet:0,unknown:0};for(let S of a)if(S.eventType==="open"||S.eventType==="click"){let E=S.userAgent.toLowerCase();if(E.includes("mobile"))T.mobile++;else if(E.includes("tablet"))T.tablet++;else if(E.includes("mozilla"))T.desktop++;else T.unknown++}let w={id:t,campaignId:e.campaignId,startDate:e.startDate,endDate:e.endDate,totalSent:r,totalDelivered:n,totalOpened:i,totalClicked:s,totalBounced:o,totalComplaints:c,deliveryRate:l,openRate:u,clickRate:m,clickToOpenRate:p,bounceRate:g,complaintRate:h,topLinks:b,deviceBreakdown:T,locationBreakdown:{}};return this.reports.set(t,w),w}createABTest(e){let t=`abtest-${Date.now()}-${this.abTestCounter++}`,a={id:t,name:e.name,variants:e.variants.map((r,n)=>({id:`variant-${t}-${n}`,sentCount:0,openCount:0,clickCount:0,conversionCount:0,...r})),status:"draft"};return this.abTests.set(t,a),a}startABTest(e){let t=this.abTests.get(e);if(!t)throw Error(`A/B test not found: ${e}`);return t.status="running",t.startedAt=new Date,t}completeABTest(e){let t=this.abTests.get(e);if(!t)throw Error(`A/B test not found: ${e}`);let a=t.variants[0],r=0;for(let n of t.variants){let i=n.sentCount>0?n.openCount/n.sentCount:0;if(i>r)r=i,a=n}return t.status="completed",t.completedAt=new Date,t.winner=a.id,t}getCampaign(e){return this.campaigns.get(e)}listCampaigns(){return Array.from(this.campaigns.values())}getEvents(e){let t=Array.from(this.events.values());if(e?.messageId)t=t.filter((a)=>a.messageId===e.messageId);if(e?.eventType)t=t.filter((a)=>a.eventType===e.eventType);if(e?.startDate)t=t.filter((a)=>a.timestamp>=e.startDate);if(e?.endDate)t=t.filter((a)=>a.timestamp<=e.endDate);return t}generateTrackingConfigurationCF(e){return{Type:"AWS::SES::ConfigurationSet",Properties:{Name:e.configurationSetName,...e.openTracking&&{TrackingOptions:{CustomRedirectDomain:"tracking.example.com"}}}}}clear(){this.events.clear(),this.campaigns.clear(),this.reports.clear(),this.abTests.clear(),this.eventCounter=0,this.campaignCounter=0,this.reportCounter=0,this.abTestCounter=0}}var km=new tn;class an{dashboards=new Map;warmupPlans=new Map;domainReputations=new Map;dashboardCounter=0;warmupCounter=0;domainCounter=0;getReputationDashboard(){let e=`dashboard-${Date.now()}-${this.dashboardCounter++}`,t=Math.random()*5,a=Math.random()*0.5,r=Math.floor(Math.random()*10),n=Math.max(0,100-t*10-a*100-r*2),i=[];if(t>2)i.push("Reduce bounce rate by cleaning email list");if(a>0.1)i.push("Review email content and unsubscribe process");if(r>5)i.push("Improve email relevance and targeting");let s={id:e,timestamp:new Date,overallScore:n,bounceRate:t,complaintRate:a,spamReports:r,blacklistStatus:this.checkBlacklists(),dkimStatus:"VERIFIED",spfStatus:"PASS",dmarcStatus:"PASS",sendingLimits:{maxSendRate:14,max24HourSend:50000,sentLast24Hours:12000,remainingQuota:38000,quotaResetTime:new Date(Date.now()+86400000)},recommendations:i};return this.dashboards.set(e,s),s}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 t=`warmup-${Date.now()}-${this.warmupCounter++}`,a=[],r=(e.targetDailyLimit-e.initialDailyLimit)/e.durationDays;for(let i=0;i<e.durationDays;i++)a.push(Math.floor(e.initialDailyLimit+r*i));let n={id:t,name:e.name,startDate:new Date,currentDay:1,totalDays:e.durationDays,dailyLimits:a,currentLimit:a[0],status:"active"};return this.warmupPlans.set(t,n),n}createAggressiveWarmupPlan(e){return this.createWarmupPlan({name:e.name,initialDailyLimit:500,targetDailyLimit:50000,durationDays:14})}createConservativeWarmupPlan(e){return this.createWarmupPlan({name:e.name,initialDailyLimit:200,targetDailyLimit:50000,durationDays:30})}advanceWarmupPlan(e){let t=this.warmupPlans.get(e);if(!t)throw Error(`Warmup plan not found: ${e}`);if(t.currentDay<t.totalDays)t.currentDay++,t.currentLimit=t.dailyLimits[t.currentDay-1];if(t.currentDay>=t.totalDays)t.status="completed";return t}trackDomainReputation(e){let t=`domain-${Date.now()}-${this.domainCounter++}`,a=e.delivered/e.totalSent*100,r=e.delivered>0?e.opened/e.delivered*100:0,n=e.delivered>0?e.clicked/e.delivered*100:0,i=e.bounced/e.totalSent*100,s=e.delivered>0?e.complained/e.delivered*100:0,o=r*0.4+n*0.6,c=Math.max(0,100-i*10-s*100+o*0.2),l={id:t,domain:e.domain,reputationScore:c,totalSent:e.totalSent,deliveryRate:a,openRate:r,clickRate:n,bounceRate:i,complaintRate:s,engagementScore:o};return this.domainReputations.set(e.domain,l),l}getDomainReputation(e){return this.domainReputations.get(e)}listDomainReputations(){return Array.from(this.domainReputations.values())}getWarmupPlan(e){return this.warmupPlans.get(e)}listWarmupPlans(){return Array.from(this.warmupPlans.values())}clear(){this.dashboards.clear(),this.warmupPlans.clear(),this.domainReputations.clear(),this.dashboardCounter=0,this.warmupCounter=0,this.domainCounter=0}}var Mm=new an;class rn{templates=new Map;versions=new Map;tests=new Map;templateCounter=0;testCounter=0;createTemplate(e){let t=`template-${Date.now()}-${this.templateCounter++}`,a=this.extractVariables(e.subject+e.htmlPart+e.textPart),r={id:t,variables:a,createdAt:new Date,updatedAt:new Date,version:1,...e};return this.templates.set(t,r),this.addVersion({templateId:t,version:1,subject:e.subject,htmlPart:e.htmlPart,textPart:e.textPart,createdBy:"system"}),r}createWelcomeTemplate(e){return this.createTemplate({name:e.name,subject:"Welcome to {{companyName}}!",htmlPart:`
|
|
3776
|
+
COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let o={sizeBefore:t.totalSize,sizeAfter:t.totalSize*0.6,timeBefore:300,timeAfter:120},c={id:a,name:`Optimization for ${t.imageId}`,recommendations:r,estimatedSavings:o};return this.optimizations.set(a,c),c}getBuildConfig(e){return this.configs.get(e)}listBuildConfigs(){return Array.from(this.configs.values())}getMultiStageConfig(e){return this.multiStageConfigs.get(e)}listMultiStageConfigs(){return Array.from(this.multiStageConfigs.values())}getOptimization(e){return this.optimizations.get(e)}listOptimizations(){return Array.from(this.optimizations.values())}clear(){this.configs.clear(),this.multiStageConfigs.clear(),this.optimizations.clear(),this.analyses.clear(),this.configCounter=0,this.multiStageCounter=0,this.optimizationCounter=0,this.analysisCounter=0}}var bm=new Ur;class jr{registries=new Map;credentials=new Map;registryCounter=0;credentialsCounter=0;createRegistry(e){let t=`registry-${Date.now()}-${this.registryCounter++}`,a={id:t,...e};return this.registries.set(t,a),a}createECRRepository(e){return this.createRegistry({name:e.name,registryType:"ecr",repositoryUri:`123456789012.dkr.ecr.${e.region||"us-east-1"}.amazonaws.com/${e.name}`,region:e.region||"us-east-1",encryption:{encryptionType:e.encryption||"AES256",kmsKeyId:e.kmsKeyId},scanning:{scanOnPush:e.scanOnPush??!0}})}createManagedRepository(e){let t=this.createECRRepository({name:e.name,region:e.region,scanOnPush:!0,encryption:"KMS"});return t.lifecycle={id:`lifecycle-${Date.now()}`,rules:[{rulePriority:1,description:"Keep only last N images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount||10},action:{type:"expire"}},{rulePriority:2,description:"Remove images older than N days",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays||30,countUnit:"days"},action:{type:"expire"}}]},t}enableReplication(e,t){let a=this.registries.get(e);if(!a)throw Error(`Registry not found: ${e}`);return a.replication={enabled:!0,destinations:t},a}createCredentials(e){let t=`creds-${Date.now()}-${this.credentialsCounter++}`,a={id:t,...e};return this.credentials.set(t,a),a}getRegistry(e){return this.registries.get(e)}listRegistries(){return Array.from(this.registries.values())}generateECRRepositoryCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e.name,ImageScanningConfiguration:{ScanOnPush:e.scanning?.scanOnPush??!1},EncryptionConfiguration:{EncryptionType:e.encryption?.encryptionType||"AES256",...e.encryption?.kmsKeyId&&{KmsKey:e.encryption.kmsKeyId}},ImageTagMutability:"MUTABLE",...e.lifecycle&&{LifecyclePolicy:{LifecyclePolicyText:JSON.stringify({rules:e.lifecycle.rules})}}}}}generateReplicationConfigCF(e){return{Type:"AWS::ECR::ReplicationConfiguration",Properties:{ReplicationConfiguration:{Rules:e.destinations.map((t)=>({Destinations:[{Region:t.region,...t.registryId&&{RegistryId:t.registryId}}]}))}}}}clear(){this.registries.clear(),this.credentials.clear(),this.registryCounter=0,this.credentialsCounter=0}}var Am=new jr;class Kr{meshes=new Map;virtualNodes=new Map;virtualRouters=new Map;virtualGateways=new Map;meshCounter=0;nodeCounter=0;routerCounter=0;gatewayCounter=0;createMesh(e){let t=`mesh-${Date.now()}-${this.meshCounter++}`,a={id:t,...e};return this.meshes.set(t,a),a}createAppMesh(e){return this.createMesh({name:e.name,meshType:"app_mesh",services:e.services,virtualNodes:[],virtualRouters:[],virtualGateways:[]})}createVirtualNode(e){let t=`vnode-${Date.now()}-${this.nodeCounter++}`,a={id:t,...e};return this.virtualNodes.set(t,a),a}createHTTPVirtualNode(e){return this.createVirtualNode({name:e.name,serviceName:e.serviceName,listeners:[{port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3},timeout:{perRequest:15000,idle:300000}}],serviceDiscovery:{type:"aws_cloud_map",namespace:e.namespace,serviceName:e.serviceName}})}createVirtualRouter(e){let t=`vrouter-${Date.now()}-${this.routerCounter++}`,a={id:t,...e};return this.virtualRouters.set(t,a),a}createCanaryRoute(e){return this.createVirtualRouter({name:e.name,listeners:[{port:e.port,protocol:e.protocol}],routes:[{name:"canary-route",match:{prefix:"/"},action:{weightedTargets:[{virtualNode:e.stableTarget,weight:100-e.canaryWeight},{virtualNode:e.canaryTarget,weight:e.canaryWeight}]},retryPolicy:{maxRetries:3,perRetryTimeout:5000,httpRetryEvents:["server-error","gateway-error"],tcpRetryEvents:["connection-error"]}}]})}createVirtualGateway(e){let t=`vgateway-${Date.now()}-${this.gatewayCounter++}`,a={id:t,...e};return this.virtualGateways.set(t,a),a}createIngressGateway(e){let t={port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3}};if(e.enableTLS&&e.certificateArn)t.tls={mode:"STRICT",certificate:{acm:e.certificateArn}};return this.createVirtualGateway({name:e.name,listeners:[t],logging:{accessLog:{file:{path:"/dev/stdout"}}}})}getMesh(e){return this.meshes.get(e)}listMeshes(){return Array.from(this.meshes.values())}getVirtualNode(e){return this.virtualNodes.get(e)}listVirtualNodes(){return Array.from(this.virtualNodes.values())}generateMeshCF(e){return{Type:"AWS::AppMesh::Mesh",Properties:{MeshName:e.name,Spec:{EgressFilter:{Type:"ALLOW_ALL"}}}}}generateVirtualNodeCF(e,t){return{Type:"AWS::AppMesh::VirtualNode",Properties:{MeshName:t,VirtualNodeName:e.name,Spec:{Listeners:e.listeners.map((a)=>({PortMapping:{Port:a.port,Protocol:a.protocol},...a.healthCheck&&{HealthCheck:{Protocol:a.healthCheck.protocol,...a.healthCheck.path&&{Path:a.healthCheck.path},IntervalMillis:a.healthCheck.interval*1000,TimeoutMillis:a.healthCheck.timeout*1000,HealthyThreshold:a.healthCheck.healthyThreshold,UnhealthyThreshold:a.healthCheck.unhealthyThreshold}}})),ServiceDiscovery:{AWSCloudMap:{NamespaceName:e.serviceDiscovery.namespace,ServiceName:e.serviceDiscovery.serviceName}}}}}}generateVirtualRouterCF(e,t){return{Type:"AWS::AppMesh::VirtualRouter",Properties:{MeshName:t,VirtualRouterName:e.name,Spec:{Listeners:e.listeners.map((a)=>({PortMapping:{Port:a.port,Protocol:a.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 Cm=new Kr;class Hr{layers=new Map;versions=new Map;permissions=new Map;layerCounter=0;versionCounter=0;permissionCounter=0;createLayer(e){let t=`layer-${Date.now()}-${this.layerCounter++}`,a=1,r={id:t,layerArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:1`,version:1,...e};return this.layers.set(t,r),r}createNodeDependenciesLayer(e){return this.createLayer({layerName:e.layerName,description:"Node.js dependencies layer",compatibleRuntimes:[`nodejs${e.nodeVersion}`],content:{type:"s3",s3Bucket:e.s3Bucket,s3Key:e.s3Key},size:5242880})}createUtilitiesLayer(e){return this.createLayer({layerName:e.layerName,description:"Shared utilities and helpers",compatibleRuntimes:e.runtimes,content:{type:"s3",s3Bucket:e.s3Bucket,s3Key:e.s3Key},size:1048576})}publishVersion(e){let t=this.layers.get(e);if(!t)throw Error(`Layer not found: ${e}`);let a=`version-${Date.now()}-${this.versionCounter++}`,r=t.version+1,n={id:a,layerName:t.layerName,version:r,createdAt:new Date,compatibleRuntimes:t.compatibleRuntimes,size:t.size,codeHash:this.generateHash()};return this.versions.set(a,n),t.version=r,t.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${t.layerName}:${r}`,n}addPermission(e){let t=`permission-${Date.now()}-${this.permissionCounter++}`,a={id:t,layerName:e.layerName,version:e.version,principal:e.principal,action:"lambda:GetLayerVersion",organizationId:e.organizationId};return this.permissions.set(t,a),a}generateHash(){return Math.random().toString(36).substring(2,15)}getLayer(e){return this.layers.get(e)}listLayers(){return Array.from(this.layers.values())}getLayerVersions(e){return Array.from(this.versions.values()).filter((t)=>t.layerName===e)}generateLayerCF(e){return{Type:"AWS::Lambda::LayerVersion",Properties:{LayerName:e.layerName,Description:e.description,Content:e.content.type==="s3"?{S3Bucket:e.content.s3Bucket,S3Key:e.content.s3Key,...e.content.s3ObjectVersion&&{S3ObjectVersion:e.content.s3ObjectVersion}}:{ZipFile:e.content.zipFile},CompatibleRuntimes:e.compatibleRuntimes,...e.licenseInfo&&{LicenseInfo:e.licenseInfo}}}}generateLayerPermissionCF(e){return{Type:"AWS::Lambda::LayerVersionPermission",Properties:{LayerVersionArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:${e.version}`,Action:e.action,Principal:e.principal,...e.organizationId&&{OrganizationId:e.organizationId}}}}clear(){this.layers.clear(),this.versions.clear(),this.permissions.clear(),this.layerCounter=0,this.versionCounter=0,this.permissionCounter=0}}var Tm=new Hr;class qr{versions=new Map;aliases=new Map;deployments=new Map;versionCounter=0;aliasCounter=0;deploymentCounter=0;publishVersion(e){let t=`version-${Date.now()}-${this.versionCounter++}`,a=this.getNextVersionNumber(e.functionName),r={id:t,functionName:e.functionName,version:a.toString(),functionArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${a}`,codeHash:this.generateHash(),description:e.description,runtime:e.runtime,memorySize:e.memorySize,timeout:e.timeout,publishedAt:new Date};return this.versions.set(t,r),r}getNextVersionNumber(e){let t=Array.from(this.versions.values()).filter((a)=>a.functionName===e).map((a)=>parseInt(a.version));return t.length>0?Math.max(...t)+1:1}createAlias(e){let t=`alias-${Date.now()}-${this.aliasCounter++}`,a={id:t,aliasArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${e.aliasName}`,revisionId:this.generateHash(),...e};return this.aliases.set(t,a),a}createProductionAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"production",functionVersion:e.version,description:"Production alias"})}createStagingAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"staging",functionVersion:e.version,description:"Staging alias"})}updateAlias(e,t){let a=this.aliases.get(e);if(!a)throw Error(`Alias not found: ${e}`);return a.functionVersion=t,a.revisionId=this.generateHash(),a}configureWeightedRouting(e,t){let a=this.aliases.get(e);if(!a)throw Error(`Alias not found: ${e}`);return a.routingConfig={additionalVersionWeights:t},a}createCanaryDeployment(e){let t=`deployment-${Date.now()}-${this.deploymentCounter++}`,a=Array.from(this.aliases.values()).find((n)=>n.functionName===e.functionName&&n.aliasName===e.aliasName);if(!a)a=this.createAlias({functionName:e.functionName,aliasName:e.aliasName,functionVersion:e.fromVersion});this.configureWeightedRouting(a.id,{[e.toVersion]:e.canaryWeight});let r={id:t,functionName:e.functionName,fromVersion:e.fromVersion,toVersion:e.toVersion,aliasName:e.aliasName,strategy:"canary",status:"in_progress",startedAt:new Date};return this.deployments.set(t,r),r}completeDeployment(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);let a=Array.from(this.aliases.values()).find((r)=>r.functionName===t.functionName&&r.aliasName===t.aliasName);if(a)a.functionVersion=t.toVersion,a.routingConfig=void 0;return t.status="completed",t.completedAt=new Date,t}rollbackDeployment(e){let t=this.deployments.get(e);if(!t)throw Error(`Deployment not found: ${e}`);let a=Array.from(this.aliases.values()).find((r)=>r.functionName===t.functionName&&r.aliasName===t.aliasName);if(a)a.functionVersion=t.fromVersion,a.routingConfig=void 0;return t.status="failed",t.completedAt=new Date,t}generateHash(){return Math.random().toString(36).substring(2,15)}getVersion(e){return this.versions.get(e)}listVersions(e){let t=Array.from(this.versions.values());return e?t.filter((a)=>a.functionName===e):t}getAlias(e){return this.aliases.get(e)}listAliases(e){let t=Array.from(this.aliases.values());return e?t.filter((a)=>a.functionName===e):t}generateVersionCF(e){return{Type:"AWS::Lambda::Version",Properties:{FunctionName:e.functionName,Description:e.description}}}generateAliasCF(e){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.functionName,Name:e.aliasName,FunctionVersion:e.functionVersion,Description:e.description,...e.routingConfig&&{RoutingConfig:{AdditionalVersionWeights:Object.entries(e.routingConfig.additionalVersionWeights||{}).map(([t,a])=>({FunctionVersion:t,FunctionWeight:a}))}}}}}clear(){this.versions.clear(),this.aliases.clear(),this.deployments.clear(),this.versionCounter=0,this.aliasCounter=0,this.deploymentCounter=0}}var vm=new qr;class zr{configs=new Map;provisionedConfigs=new Map;schedules=new Map;autoScalingConfigs=new Map;configCounter=0;provisionedCounter=0;scheduleCounter=0;autoScalingCounter=0;setReservedConcurrency(e){let t=`concurrency-${Date.now()}-${this.configCounter++}`,a={id:t,functionName:e.functionName,reservedConcurrency:e.reservedConcurrency};return this.configs.set(t,a),a}setProvisionedConcurrency(e){let t=`provisioned-${Date.now()}-${this.provisionedCounter++}`,a={id:t,functionName:e.functionName,qualifier:e.qualifier,provisionedConcurrentExecutions:e.provisionedConcurrentExecutions,status:"pending",lastModified:new Date};return this.provisionedConfigs.set(t,a),setTimeout(()=>{a.status="ready",a.allocatedConcurrency=e.provisionedConcurrentExecutions,a.availableConcurrency=e.provisionedConcurrentExecutions},100),a}configureWarmPool(e){return this.setProvisionedConcurrency({functionName:e.functionName,qualifier:e.alias,provisionedConcurrentExecutions:e.minInstances})}createSchedule(e){let t=`schedule-${Date.now()}-${this.scheduleCounter++}`,a={id:t,...e};return this.schedules.set(t,a),a}createBusinessHoursSchedule(e){return this.createSchedule({name:`${e.functionName}-business-hours`,functionName:e.functionName,qualifier:e.qualifier,schedule:[{name:"business-hours",cronExpression:"0 8 * * MON-FRI",targetConcurrency:e.businessHoursConcurrency},{name:"off-hours",cronExpression:"0 18 * * MON-FRI",targetConcurrency:e.offHoursConcurrency},{name:"weekend",cronExpression:"0 0 * * SAT",targetConcurrency:e.offHoursConcurrency}]})}configureAutoScaling(e){let t=`autoscaling-${Date.now()}-${this.autoScalingCounter++}`,a={id:t,...e};return this.autoScalingConfigs.set(t,a),a}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 wm=new zr;class Qr{destinations=new Map;records=new Map;eventBridgeDestinations=new Map;destinationCounter=0;recordCounter=0;eventBridgeCounter=0;configureDestinations(e){let t=`destination-${Date.now()}-${this.destinationCounter++}`,a={id:t,...e};return this.destinations.set(t,a),a}configureSQSDestination(e){let t={type:"sqs",arn:e.queueArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureSNSDestination(e){let t={type:"sns",arn:e.topicArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureEventBridgeDestination(e){let t={type:"eventbridge",arn:e.eventBusArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureLambdaDestination(e){let t={type:"lambda",arn:e.destinationFunctionArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?t:void 0,failureDestination:e.onFailure?t:void 0,maxEventAge:21600,maxRetries:2})}configureDLQWithNotification(e){return this.configureDestinations({functionName:e.functionName,failureDestination:{type:"sqs",arn:e.dlqArn},maxEventAge:3600,maxRetries:0})}createEventBridgeIntegration(e){let t=`eventbridge-${Date.now()}-${this.eventBridgeCounter++}`,a={id:t,functionName:e.functionName,eventBusArn:e.eventBusArn,detailType:e.detailType||"Lambda Function Invocation Result",source:e.source||`lambda.${e.functionName}`};return this.eventBridgeDestinations.set(t,a),a}sendToDestination(e){let t=Array.from(this.destinations.values()).find((i)=>i.functionName===e.functionName);if(!t)return null;let a=e.status==="success"?t.successDestination:t.failureDestination;if(!a)return null;let r=`record-${Date.now()}-${this.recordCounter++}`,n={id:r,timestamp:new Date,functionName:e.functionName,requestId:e.requestId,status:e.status,destinationType:a.type,destinationArn:a.arn,payload:e.payload,error:e.error};return this.records.set(r,n),n}getDestination(e){return this.destinations.get(e)}listDestinations(e){let t=Array.from(this.destinations.values());return e?t.filter((a)=>a.functionName===e):t}getDestinationRecords(e){let t=Array.from(this.records.values());return e?t.filter((a)=>a.functionName===e):t}generateEventInvokeConfigCF(e){return{Type:"AWS::Lambda::EventInvokeConfig",Properties:{FunctionName:e.functionName,Qualifier:e.qualifier||"$LATEST",MaximumEventAgeInSeconds:e.maxEventAge||21600,MaximumRetryAttempts:e.maxRetries??2,...e.successDestination&&{DestinationConfig:{OnSuccess:{Destination:e.successDestination.arn}}},...e.failureDestination&&{DestinationConfig:{OnFailure:{Destination:e.failureDestination.arn}}}}}}generateEventBridgeRuleCF(e){return{Type:"AWS::Events::Rule",Properties:{EventBusName:e.eventBusArn.split("/").pop(),EventPattern:{source:[e.source],"detail-type":[e.detailType]},State:"ENABLED",Targets:[{Arn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}`,Id:e.id}]}}}clear(){this.destinations.clear(),this.records.clear(),this.eventBridgeDestinations.clear(),this.destinationCounter=0,this.recordCounter=0,this.eventBridgeCounter=0}}var Em=new Qr;class Jr{vpcConfigs=new Map;endpoints=new Map;networkInterfaces=new Map;connectivity=new Map;configCounter=0;endpointCounter=0;eniCounter=0;connectivityCounter=0;configureVPC(e){let t=`vpc-config-${Date.now()}-${this.configCounter++}`,a={id:t,...e};this.vpcConfigs.set(t,a);for(let r of e.subnetIds)this.createNetworkInterface({functionName:e.functionName,subnetId:r});return a}configurePrivateVPC(e){return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.privateSubnetIds,securityGroupIds:[e.securityGroupId],ipv6Allowed:!1})}configureMultiAZVPC(e){if(e.subnetIds.length<2)throw Error("Multi-AZ configuration requires at least 2 subnets");return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds})}createVPCEndpoint(e){let t=`endpoint-${Date.now()}-${this.endpointCounter++}`,a={id:t,...e};return this.endpoints.set(t,a),a}createS3Endpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.s3",endpointType:"Gateway",privateDnsEnabled:!1})}createDynamoDBEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.dynamodb",endpointType:"Gateway",privateDnsEnabled:!1})}createSecretsManagerEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.secretsmanager",endpointType:"Interface",subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds,privateDnsEnabled:!0})}createNetworkInterface(e){let t=`eni-${Date.now()}-${this.eniCounter++}`,a={id:t,functionName:e.functionName,networkInterfaceId:`eni-${Math.random().toString(36).substring(2,15)}`,subnetId:e.subnetId,privateIpAddress:`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`,status:"creating",attachedAt:new Date};return this.networkInterfaces.set(t,a),setTimeout(()=>{a.status="available"},100),a}analyzeConnectivity(e){let t=`connectivity-${Date.now()}-${this.connectivityCounter++}`,a=Array.from(this.vpcConfigs.values()).find((c)=>c.functionName===e.functionName),r=Array.from(this.endpoints.values()).filter((c)=>c.vpcId===a?.vpcId).map((c)=>c.serviceName),n=[],i=e.hasNATGateway??!1,s=e.hasInternetGateway??!1;if(!i&&!s)n.push("Add NAT Gateway for internet access");if(!r.includes("com.amazonaws.us-east-1.s3"))n.push("Add S3 VPC endpoint to reduce NAT costs");if(!r.includes("com.amazonaws.us-east-1.dynamodb"))n.push("Add DynamoDB VPC endpoint for private access");let o={id:t,functionName:e.functionName,hasInternetAccess:i||s,hasNATGateway:i,hasVPCEndpoints:r.length>0,endpoints:r,recommendations:n};return this.connectivity.set(t,o),o}getVPCConfig(e){return this.vpcConfigs.get(e)}listVPCConfigs(e){let t=Array.from(this.vpcConfigs.values());return e?t.filter((a)=>a.functionName===e):t}getNetworkInterfaces(e){return Array.from(this.networkInterfaces.values()).filter((t)=>t.functionName===e)}listVPCEndpoints(e){let t=Array.from(this.endpoints.values());return e?t.filter((a)=>a.vpcId===e):t}generateVPCConfigCF(e){return{VpcConfig:{SubnetIds:e.subnetIds,SecurityGroupIds:e.securityGroupIds,...e.ipv6Allowed&&{Ipv6AllowedForDualStack:!0}}}}generateVPCEndpointCF(e){return{Type:"AWS::EC2::VPCEndpoint",Properties:{VpcId:e.vpcId,ServiceName:e.serviceName,VpcEndpointType:e.endpointType,...e.subnetIds&&{SubnetIds:e.subnetIds},...e.securityGroupIds&&{SecurityGroupIds:e.securityGroupIds},...e.privateDnsEnabled!==void 0&&{PrivateDnsEnabled:e.privateDnsEnabled}}}}generateSecurityGroupCF(e){return{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:e.groupName,GroupDescription:`Security group for Lambda ${e.groupName}`,VpcId:e.vpcId,...e.ingressRules&&{SecurityGroupIngress:e.ingressRules.map((t)=>({IpProtocol:t.protocol,FromPort:t.fromPort,ToPort:t.toPort,...t.cidrIp&&{CidrIp:t.cidrIp},...t.sourceSecurityGroupId&&{SourceSecurityGroupId:t.sourceSecurityGroupId}}))},...e.egressRules&&{SecurityGroupEgress:e.egressRules.map((t)=>({IpProtocol:t.protocol,FromPort:t.fromPort,ToPort:t.toPort,CidrIp:t.cidrIp||"0.0.0.0/0"}))}}}}clear(){this.vpcConfigs.clear(),this.endpoints.clear(),this.networkInterfaces.clear(),this.connectivity.clear(),this.configCounter=0,this.endpointCounter=0,this.eniCounter=0,this.connectivityCounter=0}}var Pm=new Jr;class Yr{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(e){let t=`dlq-${Date.now()}-${this.configCounter++}`,a={id:t,...e};return this.dlqConfigs.set(t,a),a}configureSQSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.queueArn,targetType:"sqs",maxReceiveCount:e.maxReceiveCount||3,retentionPeriod:e.retentionPeriod||1209600})}configureSNSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.topicArn,targetType:"sns"})}configureDLQWithAlarm(e){let t=this.configureSQSDLQ({functionName:e.functionName,queueArn:e.queueArn});return this.createDLQAlarm({dlqConfigId:t.id,alarmName:`${e.functionName}-dlq-alarm`,threshold:e.alarmThreshold,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0}),t}sendToDLQ(e){let t=`message-${Date.now()}-${this.messageCounter++}`,a={id:t,timestamp:new Date,...e};return this.messages.set(t,a),a}createDLQAlarm(e){let t=`alarm-${Date.now()}-${this.alarmCounter++}`,a={id:t,...e};return this.alarms.set(t,a),a}createAgeAlarm(e){let t=this.dlqConfigs.get(e.dlqConfigId);if(!t)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:e.dlqConfigId,alarmName:`${t.functionName}-dlq-age-alarm`,threshold:e.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0})}async reprocessMessage(e){let t=this.messages.get(e);if(!t)throw Error(`Message not found: ${e}`);let a=Array.from(this.dlqConfigs.values()).find((i)=>i.functionName===t.functionName);if(!a)throw Error(`DLQ config not found for function: ${t.functionName}`);let r=`reprocess-${Date.now()}-${this.reprocessCounter++}`,n={id:r,dlqConfigId:a.id,messageId:e,status:"pending",startedAt:new Date};return this.reprocessing.set(r,n),setTimeout(()=>{n.status="processing",setTimeout(()=>{let i=Math.random()>0.3;if(n.status=i?"success":"failed",n.completedAt=new Date,!i)n.error="Reprocessing failed - same error occurred";else this.messages.delete(e)},100)},50),n}async batchReprocess(e){let t=this.dlqConfigs.get(e.dlqConfigId);if(!t)throw Error(`DLQ config not found: ${e.dlqConfigId}`);let a=Array.from(this.messages.values()).filter((r)=>r.functionName===t.functionName).slice(0,e.maxMessages||10).map((r)=>this.reprocessMessage(r.id));return Promise.all(a)}getDLQStats(e){let t=this.dlqConfigs.get(e);if(!t)throw Error(`DLQ config not found: ${e}`);let a=Array.from(this.messages.values()).filter((s)=>s.functionName===t.functionName),r={},n=0;for(let s of a)r[s.errorType]=(r[s.errorType]||0)+1,n+=s.attemptCount;let i=a.map((s)=>s.timestamp);return{totalMessages:a.length,oldestMessage:i.length>0?new Date(Math.min(...i.map((s)=>s.getTime()))):void 0,newestMessage:i.length>0?new Date(Math.max(...i.map((s)=>s.getTime()))):void 0,averageAttempts:a.length>0?n/a.length:0,errorTypes:r}}getDLQConfig(e){return this.dlqConfigs.get(e)}listDLQConfigs(){return Array.from(this.dlqConfigs.values())}getDLQMessages(e){let t=this.dlqConfigs.get(e);if(!t)return[];return Array.from(this.messages.values()).filter((a)=>a.functionName===t.functionName)}generateDLQCF(e){return{DeadLetterConfig:{TargetArn:e.targetArn}}}generateSQSDLQCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:`${e.functionName}-dlq`,MessageRetentionPeriod:e.retentionPeriod||1209600,...e.maxReceiveCount&&{RedrivePolicy:{deadLetterTargetArn:e.targetArn,maxReceiveCount:e.maxReceiveCount}}}}}generateDLQAlarmCF(e){let t=this.dlqConfigs.get(e.dlqConfigId);if(!t)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`DLQ alarm for ${t.functionName}`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:e.evaluationPeriods,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:t.targetArn.split(":").pop()}],...e.notificationTopicArn&&{AlarmActions:[e.notificationTopicArn]}}}}clear(){this.dlqConfigs.clear(),this.messages.clear(),this.alarms.clear(),this.reprocessing.clear(),this.configCounter=0,this.messageCounter=0,this.alarmCounter=0,this.reprocessCounter=0}}var Im=new Yr;class Zr{policies=new Map;healthChecks=new Map;trafficPolicies=new Map;policyCounter=0;healthCheckCounter=0;trafficPolicyCounter=0;createWeightedPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,type:"weighted",...e};return this.policies.set(t,a),a}createLatencyPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,type:"latency",...e};return this.policies.set(t,a),a}createFailoverPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,type:"failover",...e};return this.policies.set(t,a),a}createGeolocationPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,type:"geolocation",...e};return this.policies.set(t,a),a}createGeoproximityPolicy(e){let t=`policy-${Date.now()}-${this.policyCounter++}`,a={id:t,type:"geoproximity",...e};return this.policies.set(t,a),a}createHTTPHealthCheck(e){let t=`health-check-${Date.now()}-${this.healthCheckCounter++}`,a={id:t,type:e.port===443?"https":"http",requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",port:e.port||(e.port===443?443:80),...e};return this.healthChecks.set(t,a),setTimeout(()=>{a.healthCheckStatus=Math.random()>0.2?"Healthy":"Unhealthy"},100),a}createTCPHealthCheck(e){let t=`health-check-${Date.now()}-${this.healthCheckCounter++}`,a={id:t,type:"tcp",fullyQualifiedDomainName:e.ipAddress,requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(t,a),setTimeout(()=>{a.healthCheckStatus=Math.random()>0.1?"Healthy":"Unhealthy"},100),a}createCalculatedHealthCheck(e){let t=`health-check-${Date.now()}-${this.healthCheckCounter++}`,a={id:t,type:"calculated",requestInterval:30,failureThreshold:0,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(t,a),setTimeout(()=>{let r=e.childHealthChecks.filter((n)=>this.healthChecks.get(n)?.healthCheckStatus==="Healthy").length;a.healthCheckStatus=r>=e.healthThreshold?"Healthy":"Unhealthy"},150),a}createTrafficPolicy(e){let t=`traffic-policy-${Date.now()}-${this.trafficPolicyCounter++}`,a={id:t,version:1,...e};return this.trafficPolicies.set(t,a),a}createFailoverTrafficPolicy(e){return this.createTrafficPolicy({name:e.name,document:{recordType:e.recordType||"A",startRule:"failover",endpoints:{primary:{type:"value",value:e.primaryEndpoint},secondary:{type:"value",value:e.secondaryEndpoint}},rules:{failover:{ruleType:"failover",primary:"primary",secondary:"secondary"}}}})}createGeoproximityTrafficPolicy(e){let t={},a=[];return e.locations.forEach((r,n)=>{let i=`endpoint${n}`;t[i]={type:"value",value:r.endpoint},a.push({endpointReference:i,region:r.region,latitude:r.latitude,longitude:r.longitude,bias:r.bias})}),this.createTrafficPolicy({name:e.name,document:{recordType:"A",startRule:"geoproximity",endpoints:t,rules:{geoproximity:{ruleType:"geoproximity",locations:a}}}})}getPolicy(e){return this.policies.get(e)}listPolicies(){return Array.from(this.policies.values())}getHealthCheck(e){return this.healthChecks.get(e)}listHealthChecks(){return Array.from(this.healthChecks.values())}getHealthCheckStatus(e){return this.healthChecks.get(e)?.healthCheckStatus||"Unknown"}generateHealthCheckCF(e){let t={Type:"AWS::Route53::HealthCheck",Properties:{HealthCheckConfig:{Type:e.type.toUpperCase(),RequestInterval:e.requestInterval,FailureThreshold:e.failureThreshold,...e.measureLatency&&{MeasureLatency:!0}},HealthCheckTags:[{Key:"Name",Value:e.name}]}};if(e.type==="calculated"){let a=e;t.Properties.HealthCheckConfig.ChildHealthChecks=a.childHealthChecks,t.Properties.HealthCheckConfig.HealthThreshold=a.healthThreshold}else{if(e.ipAddress)t.Properties.HealthCheckConfig.IPAddress=e.ipAddress;if(e.fullyQualifiedDomainName)t.Properties.HealthCheckConfig.FullyQualifiedDomainName=e.fullyQualifiedDomainName;if(e.port)t.Properties.HealthCheckConfig.Port=e.port;if(e.resourcePath)t.Properties.HealthCheckConfig.ResourcePath=e.resourcePath;if(e.enableSNI)t.Properties.HealthCheckConfig.EnableSNI=!0}return t}generateWeightedRecordSetCF(e){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.hostedZoneId,Name:e.name,Type:e.type,TTL:e.ttl,ResourceRecords:e.resourceRecords,Weight:e.weight,SetIdentifier:e.setIdentifier,...e.healthCheckId&&{HealthCheckId:e.healthCheckId}}}}generateFailoverRecordSetCF(e){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.hostedZoneId,Name:e.name,Type:e.type,TTL:e.ttl,ResourceRecords:e.resourceRecords,Failover:e.failover,SetIdentifier:e.setIdentifier,...e.healthCheckId&&{HealthCheckId:e.healthCheckId}}}}clear(){this.policies.clear(),this.healthChecks.clear(),this.trafficPolicies.clear(),this.policyCounter=0,this.healthCheckCounter=0,this.trafficPolicyCounter=0}}var Rm=new Zr;class Xr{configs=new Map;ksks=new Map;validations=new Map;configCounter=0;kskCounter=0;validationCounter=0;enableDNSSEC(e){let t=`dnssec-${Date.now()}-${this.configCounter++}`,a={id:t,hostedZoneId:e.hostedZoneId,status:"SIGNING",signingStatus:"Initializing DNSSEC signing"};if(this.configs.set(t,a),e.kmsKeyArn)this.createKSK({name:`ksk-${e.hostedZoneId}`,hostedZoneId:e.hostedZoneId,kmsKeyArn:e.kmsKeyArn});return setTimeout(()=>{a.status="SIGNED",a.signingStatus="DNSSEC signing complete"},100),a}disableDNSSEC(e){let t=this.configs.get(e);if(!t)throw Error(`DNSSEC config not found: ${e}`);return t.status="DELETING",t.signingStatus="Removing DNSSEC signing",setTimeout(()=>{t.status="NOT_SIGNING",t.signingStatus="DNSSEC signing removed"},100),t}createKSK(e){let t=`ksk-${Date.now()}-${this.kskCounter++}`,a={id:t,status:"ACTIVE",flag:257,keyManagementServiceArn:e.kmsKeyArn,digestAlgorithm:2,keyTag:Math.floor(Math.random()*65535),publicKey:this.generatePublicKey(),...e};a.dnskeyRecord=`${a.flag} 3 8 ${a.publicKey}`;let r=this.generateDigest(a.dnskeyRecord);return a.digestValue=r,a.dsRecord=`${a.keyTag} 8 ${a.digestAlgorithm} ${r}`,this.ksks.set(t,a),a}deactivateKSK(e){let t=this.ksks.get(e);if(!t)throw Error(`KSK not found: ${e}`);return t.status="INACTIVE",t}validateDNSSEC(e){let t=`validation-${Date.now()}-${this.validationCounter++}`,a=e.checkDNSKEY!==!1?Math.random()>0.1:!1,r=e.checkRRSIG!==!1?Math.random()>0.1:!1,n=a&&r,i=[];if(!a)i.push("DNSKEY record not found");if(!r)i.push("RRSIG record not found");let s;if(!a&&!r)s="INSECURE";else if(a&&r&&n)s="VALID";else if(a||r)s="BOGUS",i.push("Invalid signature or incomplete DNSSEC chain");else s="INVALID";let o={id:t,domain:e.domain,validationStatus:s,dnskeyPresent:a,rrsigPresent:r,validSignature:n,errors:i};return this.validations.set(t,o),o}getDNSSECConfig(e){return this.configs.get(e)}listDNSSECConfigs(){return Array.from(this.configs.values())}getKSK(e){return this.ksks.get(e)}listKSKs(e){let t=Array.from(this.ksks.values());return e?t.filter((a)=>a.hostedZoneId===e):t}getDSRecord(e){let t=this.ksks.get(e);if(!t||!t.dsRecord)throw Error("DS record not available");return t.dsRecord}generatePublicKey(){let e="";for(let t=0;t<256;t++)e+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return e}generateDigest(e){let t="";for(let a=0;a<64;a++)t+="0123456789ABCDEF".charAt(Math.floor(Math.random()*16));return t}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 Nm=new Xr;class en{endpoints=new Map;rules=new Map;firewalls=new Map;ruleGroups=new Map;domainLists=new Map;endpointCounter=0;ruleCounter=0;firewallCounter=0;ruleGroupCounter=0;domainListCounter=0;createResolverEndpoint(e){let t=`endpoint-${Date.now()}-${this.endpointCounter++}`,a={id:t,status:"CREATING",...e};return this.endpoints.set(t,a),setTimeout(()=>{a.status="OPERATIONAL",a.ipAddresses.forEach((r)=>{if(!r.ip)r.ip=`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`})},100),a}createInboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"INBOUND",ipAddresses:e.subnetIds.map((t)=>({subnetId:t})),securityGroupIds:e.securityGroupIds})}createOutboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"OUTBOUND",ipAddresses:e.subnetIds.map((t)=>({subnetId:t})),securityGroupIds:e.securityGroupIds})}createResolverRule(e){let t=`rule-${Date.now()}-${this.ruleCounter++}`,a={id:t,status:"CREATING",...e};return this.rules.set(t,a),setTimeout(()=>{a.status="COMPLETE"},100),a}createForwardRule(e){return this.createResolverRule({name:e.name,ruleType:"FORWARD",domainName:e.domainName,targetIps:e.targetIps,resolverEndpointId:e.resolverEndpointId})}createSystemRule(e){return this.createResolverRule({name:e.name,ruleType:"SYSTEM",domainName:e.domainName})}createFirewallDomainList(e){let t=`domain-list-${Date.now()}-${this.domainListCounter++}`,a={id:t,status:"CREATING",...e};return this.domainLists.set(t,a),setTimeout(()=>{a.status="COMPLETE"},100),a}createFirewallRuleGroup(e){let t=`rule-group-${Date.now()}-${this.ruleGroupCounter++}`,a={id:t,name:e.name,rules:e.rules.map((r,n)=>({id:`rule-${t}-${n}`,...r})),shareStatus:"NOT_SHARED"};return this.ruleGroups.set(t,a),a}createBlockRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"BLOCK",blockResponse:e.blockResponse||"NODATA",blockOverrideDomain:e.blockOverrideDomain,firewallDomainListId:e.domainListId}]})}createAllowRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"ALLOW",firewallDomainListId:e.domainListId}]})}createDNSFirewall(e){let t=`firewall-${Date.now()}-${this.firewallCounter++}`,a={id:t,name:e.name,firewallRuleGroupAssociations:e.ruleGroupAssociations.map((r,n)=>({id:`assoc-${t}-${n}`,vpcId:e.vpcId,firewallRuleGroupId:r.firewallRuleGroupId,priority:r.priority,mutationProtection:r.mutationProtection||"DISABLED",status:"COMPLETE"}))};return this.firewalls.set(t,a),a}createMalwareProtectionFirewall(e){let t=this.createFirewallDomainList({name:`${e.name}-malware-domains`,domains:e.maliciousDomains}),a=this.createBlockRule({name:`${e.name}-block-malware`,priority:100,domainListId:t.id,blockResponse:"NXDOMAIN"});return this.createDNSFirewall({name:e.name,vpcId:e.vpcId,ruleGroupAssociations:[{firewallRuleGroupId:a.id,priority:100,mutationProtection:"ENABLED"}]})}getEndpoint(e){return this.endpoints.get(e)}listEndpoints(e){let t=Array.from(this.endpoints.values());return e?t.filter((a)=>a.direction===e):t}getRule(e){return this.rules.get(e)}listRules(){return Array.from(this.rules.values())}getFirewall(e){return this.firewalls.get(e)}listFirewalls(){return Array.from(this.firewalls.values())}generateResolverEndpointCF(e){return{Type:"AWS::Route53Resolver::ResolverEndpoint",Properties:{Name:e.name,Direction:e.direction,IpAddresses:e.ipAddresses.map((t)=>({SubnetId:t.subnetId,...t.ip&&{Ip:t.ip}})),SecurityGroupIds:e.securityGroupIds}}}generateResolverRuleCF(e){return{Type:"AWS::Route53Resolver::ResolverRule",Properties:{Name:e.name,RuleType:e.ruleType,DomainName:e.domainName,...e.targetIps&&{TargetIps:e.targetIps.map((t)=>({Ip:t.ip,Port:t.port||53}))},...e.resolverEndpointId&&{ResolverEndpointId:e.resolverEndpointId}}}}generateFirewallRuleGroupCF(e){return{Type:"AWS::Route53Resolver::FirewallRuleGroup",Properties:{Name:e.name,FirewallRules:e.rules.map((t)=>({Name:t.name,Priority:t.priority,Action:t.action,FirewallDomainListId:t.firewallDomainListId,...t.blockResponse&&{BlockResponse:t.blockResponse},...t.blockOverrideDomain&&{BlockOverrideDomain:t.blockOverrideDomain},...t.blockOverrideTTL&&{BlockOverrideTtl:t.blockOverrideTTL}}))}}}clear(){this.endpoints.clear(),this.rules.clear(),this.firewalls.clear(),this.ruleGroups.clear(),this.domainLists.clear(),this.endpointCounter=0,this.ruleCounter=0,this.firewallCounter=0,this.ruleGroupCounter=0,this.domainListCounter=0}}var Dm=new en;class tn{bounces=new Map;complaints=new Map;handlers=new Map;suppressionList=new Map;metrics=new Map;bounceCounter=0;complaintCounter=0;handlerCounter=0;suppressionCounter=0;metricsCounter=0;recordBounce(e){let t=`bounce-${Date.now()}-${this.bounceCounter++}`,a={id:t,...e};if(this.bounces.set(t,a),e.bounceType==="Permanent")this.addToSuppressionList({emailAddress:e.recipient,reason:"BOUNCE"});return a}recordComplaint(e){let t=`complaint-${Date.now()}-${this.complaintCounter++}`,a={id:t,...e};this.complaints.set(t,a);for(let r of e.recipients)this.addToSuppressionList({emailAddress:r,reason:"COMPLAINT"});return a}createBounceHandler(e){let t=`handler-${Date.now()}-${this.handlerCounter++}`,a={id:t,...e};return this.handlers.set(t,a),a}createAutomaticBounceHandler(e){return this.createBounceHandler({name:e.name,bounceThreshold:5,complaintThreshold:0.1,suppressionDuration:2592000,autoSuppress:!0,notificationTopicArn:e.notificationTopicArn})}addToSuppressionList(e){let t=`suppression-${Date.now()}-${this.suppressionCounter++}`,a=e.expirationDays?new Date(Date.now()+e.expirationDays*24*60*60*1000):void 0,r={id:t,emailAddress:e.emailAddress,reason:e.reason,suppressedAt:new Date,expiresAt:a,bounceCount:e.reason==="BOUNCE"?1:0,complaintCount:e.reason==="COMPLAINT"?1:0};return this.suppressionList.set(e.emailAddress,r),r}removeFromSuppressionList(e){return this.suppressionList.delete(e)}isSuppressed(e){let t=this.suppressionList.get(e);if(!t)return!1;if(t.expiresAt&&t.expiresAt<new Date)return this.suppressionList.delete(e),!1;return!0}getBounceStatistics(e,t){let a=Array.from(this.bounces.values()).filter((u)=>u.timestamp>=e&&u.timestamp<=t),r=a.length,n=a.filter((u)=>u.bounceType==="Permanent").length,i=a.filter((u)=>u.bounceType==="Transient").length,s=r*10,o=r/s*100,c=new Map;for(let u of a)c.set(u.recipient,(c.get(u.recipient)||0)+1);let l=Array.from(c.entries()).map(([u,m])=>({email:u,count:m})).sort((u,m)=>m.count-u.count).slice(0,10);return{totalBounces:r,permanentBounces:n,transientBounces:i,bounceRate:o,topRecipients:l}}getComplaintStatistics(e,t){let a=Array.from(this.complaints.values()).filter((c)=>c.timestamp>=e&&c.timestamp<=t),r=a.length,n=new Set;for(let c of a)for(let l of c.recipients)n.add(l);let i=n.size,s=r*1000,o=r/s*100;return{totalComplaints:r,uniqueComplainters:i,complaintRate:o}}calculateReputationMetrics(){let e=`metrics-${Date.now()}-${this.metricsCounter++}`,t=new Date,a=new Date(t.getTime()-86400000),r=this.getBounceStatistics(a,t),n=this.getComplaintStatistics(a,t),i;if(r.bounceRate>10||n.complaintRate>0.5)i="Shutdown";else if(r.bounceRate>5||n.complaintRate>0.1)i="Probation";else if(r.bounceRate>2||n.complaintRate>0.05)i="Warning";else i="Good";let s={id:e,timestamp:t,bounceRate:r.bounceRate,complaintRate:n.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:r.totalBounces*10,reputationStatus:i};return this.metrics.set(e,s),s}getBounces(e){let t=Array.from(this.bounces.values());return e?t.filter((a)=>a.messageId===e):t}getComplaints(e){let t=Array.from(this.complaints.values());return e?t.filter((a)=>a.messageId===e):t}listSuppressionList(e){let t=Array.from(this.suppressionList.values());return e?t.filter((a)=>a.reason===e):t}generateSNSSubscriptionCF(e){return{Type:"AWS::SNS::Subscription",Properties:{TopicArn:e.topicArn,Endpoint:e.endpoint,Protocol:e.protocol}}}generateEventDestinationCF(e){return{Type:"AWS::SES::ConfigurationSetEventDestination",Properties:{ConfigurationSetName:e.configurationSetName,EventDestination:{Name:e.eventDestinationName,Enabled:!0,MatchingEventTypes:e.eventTypes,...e.snsTopicArn&&{SnsDestination:{TopicARN:e.snsTopicArn}},...e.cloudWatchDestination&&{CloudWatchDestination:e.cloudWatchDestination}}}}}clear(){this.bounces.clear(),this.complaints.clear(),this.handlers.clear(),this.suppressionList.clear(),this.metrics.clear(),this.bounceCounter=0,this.complaintCounter=0,this.handlerCounter=0,this.suppressionCounter=0,this.metricsCounter=0}}var km=new tn;class an{events=new Map;campaigns=new Map;reports=new Map;abTests=new Map;eventCounter=0;campaignCounter=0;reportCounter=0;abTestCounter=0;trackEvent(e){let t=`event-${Date.now()}-${this.eventCounter++}`,a={id:t,...e};if(this.events.set(t,a),e.tags?.campaignId)this.updateCampaignStats(e.tags.campaignId,e.eventType);return a}trackOpen(e){return this.trackEvent({...e,eventType:"open",timestamp:new Date})}trackClick(e){return this.trackEvent({...e,eventType:"click",timestamp:new Date})}createCampaign(e){let t=`campaign-${Date.now()}-${this.campaignCounter++}`,a={id:t,sentCount:0,deliveredCount:0,openCount:0,clickCount:0,bounceCount:0,complaintCount:0,createdAt:new Date,...e};return this.campaigns.set(t,a),a}updateCampaignStats(e,t){let a=this.campaigns.get(e);if(!a)return;switch(t){case"send":a.sentCount++;break;case"delivery":a.deliveredCount++;break;case"open":a.openCount++;break;case"click":a.clickCount++;break;case"bounce":a.bounceCount++;break;case"complaint":a.complaintCount++;break}}generateReport(e){let t=`report-${Date.now()}-${this.reportCounter++}`,a=Array.from(this.events.values()).filter((S)=>{let E=S.timestamp>=e.startDate&&S.timestamp<=e.endDate,v=!e.campaignId||S.tags?.campaignId===e.campaignId;return E&&v}),r=a.filter((S)=>S.eventType==="send").length,n=a.filter((S)=>S.eventType==="delivery").length,i=a.filter((S)=>S.eventType==="open").length,s=a.filter((S)=>S.eventType==="click").length,o=a.filter((S)=>S.eventType==="bounce").length,c=a.filter((S)=>S.eventType==="complaint").length,l=r>0?n/r*100:0,u=n>0?i/n*100:0,m=n>0?s/n*100:0,p=i>0?s/i*100:0,g=r>0?o/r*100:0,h=n>0?c/n*100:0,y=new Map;for(let S of a)if(S.eventType==="click"){let E=S;y.set(E.link,(y.get(E.link)||0)+1)}let b=Array.from(y.entries()).map(([S,E])=>({link:S,clicks:E})).sort((S,E)=>E.clicks-S.clicks).slice(0,10),T={desktop:0,mobile:0,tablet:0,unknown:0};for(let S of a)if(S.eventType==="open"||S.eventType==="click"){let E=S.userAgent.toLowerCase();if(E.includes("mobile"))T.mobile++;else if(E.includes("tablet"))T.tablet++;else if(E.includes("mozilla"))T.desktop++;else T.unknown++}let w={id:t,campaignId:e.campaignId,startDate:e.startDate,endDate:e.endDate,totalSent:r,totalDelivered:n,totalOpened:i,totalClicked:s,totalBounced:o,totalComplaints:c,deliveryRate:l,openRate:u,clickRate:m,clickToOpenRate:p,bounceRate:g,complaintRate:h,topLinks:b,deviceBreakdown:T,locationBreakdown:{}};return this.reports.set(t,w),w}createABTest(e){let t=`abtest-${Date.now()}-${this.abTestCounter++}`,a={id:t,name:e.name,variants:e.variants.map((r,n)=>({id:`variant-${t}-${n}`,sentCount:0,openCount:0,clickCount:0,conversionCount:0,...r})),status:"draft"};return this.abTests.set(t,a),a}startABTest(e){let t=this.abTests.get(e);if(!t)throw Error(`A/B test not found: ${e}`);return t.status="running",t.startedAt=new Date,t}completeABTest(e){let t=this.abTests.get(e);if(!t)throw Error(`A/B test not found: ${e}`);let a=t.variants[0],r=0;for(let n of t.variants){let i=n.sentCount>0?n.openCount/n.sentCount:0;if(i>r)r=i,a=n}return t.status="completed",t.completedAt=new Date,t.winner=a.id,t}getCampaign(e){return this.campaigns.get(e)}listCampaigns(){return Array.from(this.campaigns.values())}getEvents(e){let t=Array.from(this.events.values());if(e?.messageId)t=t.filter((a)=>a.messageId===e.messageId);if(e?.eventType)t=t.filter((a)=>a.eventType===e.eventType);if(e?.startDate)t=t.filter((a)=>a.timestamp>=e.startDate);if(e?.endDate)t=t.filter((a)=>a.timestamp<=e.endDate);return t}generateTrackingConfigurationCF(e){return{Type:"AWS::SES::ConfigurationSet",Properties:{Name:e.configurationSetName,...e.openTracking&&{TrackingOptions:{CustomRedirectDomain:"tracking.example.com"}}}}}clear(){this.events.clear(),this.campaigns.clear(),this.reports.clear(),this.abTests.clear(),this.eventCounter=0,this.campaignCounter=0,this.reportCounter=0,this.abTestCounter=0}}var $m=new an;class rn{dashboards=new Map;warmupPlans=new Map;domainReputations=new Map;dashboardCounter=0;warmupCounter=0;domainCounter=0;getReputationDashboard(){let e=`dashboard-${Date.now()}-${this.dashboardCounter++}`,t=Math.random()*5,a=Math.random()*0.5,r=Math.floor(Math.random()*10),n=Math.max(0,100-t*10-a*100-r*2),i=[];if(t>2)i.push("Reduce bounce rate by cleaning email list");if(a>0.1)i.push("Review email content and unsubscribe process");if(r>5)i.push("Improve email relevance and targeting");let s={id:e,timestamp:new Date,overallScore:n,bounceRate:t,complaintRate:a,spamReports:r,blacklistStatus:this.checkBlacklists(),dkimStatus:"VERIFIED",spfStatus:"PASS",dmarcStatus:"PASS",sendingLimits:{maxSendRate:14,max24HourSend:50000,sentLast24Hours:12000,remainingQuota:38000,quotaResetTime:new Date(Date.now()+86400000)},recommendations:i};return this.dashboards.set(e,s),s}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 t=`warmup-${Date.now()}-${this.warmupCounter++}`,a=[],r=(e.targetDailyLimit-e.initialDailyLimit)/e.durationDays;for(let i=0;i<e.durationDays;i++)a.push(Math.floor(e.initialDailyLimit+r*i));let n={id:t,name:e.name,startDate:new Date,currentDay:1,totalDays:e.durationDays,dailyLimits:a,currentLimit:a[0],status:"active"};return this.warmupPlans.set(t,n),n}createAggressiveWarmupPlan(e){return this.createWarmupPlan({name:e.name,initialDailyLimit:500,targetDailyLimit:50000,durationDays:14})}createConservativeWarmupPlan(e){return this.createWarmupPlan({name:e.name,initialDailyLimit:200,targetDailyLimit:50000,durationDays:30})}advanceWarmupPlan(e){let t=this.warmupPlans.get(e);if(!t)throw Error(`Warmup plan not found: ${e}`);if(t.currentDay<t.totalDays)t.currentDay++,t.currentLimit=t.dailyLimits[t.currentDay-1];if(t.currentDay>=t.totalDays)t.status="completed";return t}trackDomainReputation(e){let t=`domain-${Date.now()}-${this.domainCounter++}`,a=e.delivered/e.totalSent*100,r=e.delivered>0?e.opened/e.delivered*100:0,n=e.delivered>0?e.clicked/e.delivered*100:0,i=e.bounced/e.totalSent*100,s=e.delivered>0?e.complained/e.delivered*100:0,o=r*0.4+n*0.6,c=Math.max(0,100-i*10-s*100+o*0.2),l={id:t,domain:e.domain,reputationScore:c,totalSent:e.totalSent,deliveryRate:a,openRate:r,clickRate:n,bounceRate:i,complaintRate:s,engagementScore:o};return this.domainReputations.set(e.domain,l),l}getDomainReputation(e){return this.domainReputations.get(e)}listDomainReputations(){return Array.from(this.domainReputations.values())}getWarmupPlan(e){return this.warmupPlans.get(e)}listWarmupPlans(){return Array.from(this.warmupPlans.values())}clear(){this.dashboards.clear(),this.warmupPlans.clear(),this.domainReputations.clear(),this.dashboardCounter=0,this.warmupCounter=0,this.domainCounter=0}}var Lm=new rn;class nn{templates=new Map;versions=new Map;tests=new Map;templateCounter=0;testCounter=0;createTemplate(e){let t=`template-${Date.now()}-${this.templateCounter++}`,a=this.extractVariables(e.subject+e.htmlPart+e.textPart),r={id:t,variables:a,createdAt:new Date,updatedAt:new Date,version:1,...e};return this.templates.set(t,r),this.addVersion({templateId:t,version:1,subject:e.subject,htmlPart:e.htmlPart,textPart:e.textPart,createdBy:"system"}),r}createWelcomeTemplate(e){return this.createTemplate({name:e.name,subject:"Welcome to {{companyName}}!",htmlPart:`
|
|
3777
3777
|
<html>
|
|
3778
3778
|
<body>
|
|
3779
3779
|
<h1>Welcome, {{userName}}!</h1>
|
|
@@ -3793,7 +3793,7 @@ COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let o={si
|
|
|
3793
3793
|
<p>If you didn't request this, please ignore this email.</p>
|
|
3794
3794
|
</body>
|
|
3795
3795
|
</html>
|
|
3796
|
-
`,textPart:"Hi {{userName}}, reset your password at: {{resetUrl}}. This link expires in {{expirationHours}} hours."})}updateTemplate(e,t,a){let r=this.templates.get(e);if(!r)throw Error(`Template not found: ${e}`);if(t.subject)r.subject=t.subject;if(t.htmlPart)r.htmlPart=t.htmlPart;if(t.textPart)r.textPart=t.textPart;return r.version++,r.updatedAt=new Date,r.variables=this.extractVariables(r.subject+r.htmlPart+r.textPart),this.addVersion({templateId:e,version:r.version,subject:r.subject,htmlPart:r.htmlPart,textPart:r.textPart,createdBy:"system",changelog:a}),r}addVersion(e){let t={id:`version-${e.templateId}-${e.version}`,createdAt:new Date,...e},a=this.versions.get(e.templateId)||[];return a.push(t),this.versions.set(e.templateId,a),t}extractVariables(e){let t=/\{\{([^}]+)\}\}/g,a=new Set,r;while((r=t.exec(e))!==null)a.add(r[1].trim());return Array.from(a)}renderTemplate(e,t){let a=this.templates.get(e);if(!a)throw Error(`Template not found: ${e}`);let r=(n)=>
|
|
3796
|
+
`,textPart:"Hi {{userName}}, reset your password at: {{resetUrl}}. This link expires in {{expirationHours}} hours."})}updateTemplate(e,t,a){let r=this.templates.get(e);if(!r)throw Error(`Template not found: ${e}`);if(t.subject)r.subject=t.subject;if(t.htmlPart)r.htmlPart=t.htmlPart;if(t.textPart)r.textPart=t.textPart;return r.version++,r.updatedAt=new Date,r.variables=this.extractVariables(r.subject+r.htmlPart+r.textPart),this.addVersion({templateId:e,version:r.version,subject:r.subject,htmlPart:r.htmlPart,textPart:r.textPart,createdBy:"system",changelog:a}),r}addVersion(e){let t={id:`version-${e.templateId}-${e.version}`,createdAt:new Date,...e},a=this.versions.get(e.templateId)||[];return a.push(t),this.versions.set(e.templateId,a),t}extractVariables(e){let t=/\{\{([^}]+)\}\}/g,a=new Set,r;while((r=t.exec(e))!==null)a.add(r[1].trim());return Array.from(a)}renderTemplate(e,t){let a=this.templates.get(e);if(!a)throw Error(`Template not found: ${e}`);let r=(n)=>n.replace(/\{\{([^}]+)\}\}/g,(i,s)=>{let o=s.trim();return t[o]!==void 0?String(t[o]):i});return{subject:r(a.subject),html:r(a.htmlPart),text:r(a.textPart)}}testTemplate(e,t){let a=`test-${Date.now()}-${this.testCounter++}`,r=this.renderTemplate(e,t),n={id:a,templateId:e,testData:t,renderedSubject:r.subject,renderedHtml:r.html,renderedText:r.text,timestamp:new Date};return this.tests.set(a,n),n}getTemplate(e){return this.templates.get(e)}listTemplates(){return Array.from(this.templates.values())}getTemplateVersions(e){return this.versions.get(e)||[]}revertToVersion(e,t){let a=this.templates.get(e);if(!a)throw Error(`Template not found: ${e}`);let r=(this.versions.get(e)||[]).find((n)=>n.version===t);if(!r)throw Error(`Version ${t} not found for template ${e}`);return a.subject=r.subject,a.htmlPart=r.htmlPart,a.textPart=r.textPart,a.version++,a.updatedAt=new Date,this.addVersion({templateId:e,version:a.version,subject:a.subject,htmlPart:a.htmlPart,textPart:a.textPart,createdBy:"system",changelog:`Reverted to version ${t}`}),a}generateTemplateCF(e){return{Type:"AWS::SES::Template",Properties:{Template:{TemplateName:e.name,SubjectPart:e.subject,HtmlPart:e.htmlPart,TextPart:e.textPart}}}}clear(){this.templates.clear(),this.versions.clear(),this.tests.clear(),this.templateCounter=0,this.testCounter=0}}var Mm=new nn,Ao={};De(Ao,{EmailAnalyticsModule:()=>et,EmailRules:()=>aa,EmailScheduling:()=>ea,EmailSearch:()=>Zt,EmailTemplates:()=>Re,EmailThreading:()=>Xt,SharedMailboxes:()=>ta});class Zt{static createSearchDomain(e){let{slug:t,environment:a,domainName:r,instanceType:n="t3.small.search",instanceCount:i=1,ebsVolumeSize:s=10,masterUserName:o="admin",masterUserPassword:c}=e,l=r||`${t}-${a}-email-search`;return{[`${t}EmailSearchDomain`]:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:l,EngineVersion:"OpenSearch_2.11",ClusterConfig:{InstanceType:n,InstanceCount:i,DedicatedMasterEnabled:!1,ZoneAwarenessEnabled:!1},EBSOptions:{EBSEnabled:!0,VolumeType:"gp3",VolumeSize:s},NodeToNodeEncryptionOptions:{Enabled:!0},EncryptionAtRestOptions:{Enabled:!0},DomainEndpointOptions:{EnforceHTTPS:!0},AdvancedSecurityOptions:{Enabled:!0,InternalUserDatabaseEnabled:!0,MasterUserOptions:{MasterUserName:o,MasterUserPassword:c||`${t}-search-${Date.now()}`}},AccessPolicies:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:`arn:aws:es:*:*:domain/${l}/*`}]}}}}}static createIndexerLambda(e){return{[`${e.slug}EmailIndexerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-indexer`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:512,Code:{ZipFile:Zt.IndexerLambdaCode},Environment:{Variables:{OPENSEARCH_ENDPOINT:e.searchDomainEndpoint,EMAIL_BUCKET:e.emailBucket}}}}}}static IndexerLambdaCode=`
|
|
3797
3797
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
3798
3798
|
const https = require('https');
|
|
3799
3799
|
|
|
@@ -4033,7 +4033,7 @@ catch {
|
|
|
4033
4033
|
ContentType: 'application/json',
|
|
4034
4034
|
}));
|
|
4035
4035
|
}
|
|
4036
|
-
`;static createThreadingLambda(e){return{[`${e.slug}EmailThreadingLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:Xt.ThreadingLambdaCode},Environment:{Variables:{EMAIL_BUCKET:e.emailBucket}}}}}}static async getThreads(e){let{s3Client:t,bucket:a,mailbox:r,limit:n=50,offset:i=0}=e,[s,o]=r.includes("@")?r.split("@"):[r,"default"],c=`mailboxes/${o}/${s}/threads.json`;try{let l=await t.send({Bucket:a,Key:c}),u=JSON.parse(l.Body),m=Object.values(u);return m.sort((p,g)=>new Date(g.lastMessageDate).getTime()-new Date(p.lastMessageDate).getTime()),m.slice(i,i+n)}catch{return[]}}static async getThread(e){let{s3Client:t,bucket:a,mailbox:r,threadId:n}=e,[i,s]=r.includes("@")?r.split("@"):[r,"default"],o=`mailboxes/${s}/${i}/threads.json`;try{let c=await t.send({Bucket:a,Key:o});return JSON.parse(c.Body)[n]||null}catch{return null}}}class
|
|
4036
|
+
`;static createThreadingLambda(e){return{[`${e.slug}EmailThreadingLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:Xt.ThreadingLambdaCode},Environment:{Variables:{EMAIL_BUCKET:e.emailBucket}}}}}}static async getThreads(e){let{s3Client:t,bucket:a,mailbox:r,limit:n=50,offset:i=0}=e,[s,o]=r.includes("@")?r.split("@"):[r,"default"],c=`mailboxes/${o}/${s}/threads.json`;try{let l=await t.send({Bucket:a,Key:c}),u=JSON.parse(l.Body),m=Object.values(u);return m.sort((p,g)=>new Date(g.lastMessageDate).getTime()-new Date(p.lastMessageDate).getTime()),m.slice(i,i+n)}catch{return[]}}static async getThread(e){let{s3Client:t,bucket:a,mailbox:r,threadId:n}=e,[i,s]=r.includes("@")?r.split("@"):[r,"default"],o=`mailboxes/${s}/${i}/threads.json`;try{let c=await t.send({Bucket:a,Key:o});return JSON.parse(c.Body)[n]||null}catch{return null}}}class ea{static SchedulerLambdaCode=`
|
|
4037
4037
|
const { S3Client, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, ListObjectsV2Command } = require('@aws-sdk/client-s3');
|
|
4038
4038
|
const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
|
|
4039
4039
|
|
|
@@ -4162,7 +4162,7 @@ else {
|
|
|
4162
4162
|
|
|
4163
4163
|
return raw;
|
|
4164
4164
|
}
|
|
4165
|
-
`;static createSchedulerLambda(e){return{[`${e.slug}EmailSchedulerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:300,MemorySize:256,Code:{ZipFile:
|
|
4165
|
+
`;static createSchedulerLambda(e){return{[`${e.slug}EmailSchedulerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:300,MemorySize:256,Code:{ZipFile:ea.SchedulerLambdaCode},Environment:{Variables:{EMAIL_BUCKET:e.emailBucket}}}}}}static createSchedulerRule(e){return{[`${e.slug}EmailSchedulerRule`]:{Type:"AWS::Events::Rule",Properties:{Name:`${e.slug}-email-scheduler`,Description:"Trigger email scheduler every minute",ScheduleExpression:e.scheduleExpression||"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:e.lambdaArn}]}},[`${e.slug}EmailSchedulerPermission`]:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:e.lambdaArn,Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:{"Fn::GetAtt":[`${e.slug}EmailSchedulerRule`,"Arn"]}}}}}static async scheduleEmail(e){let{s3Client:t,bucket:a,email:r,scheduledFor:n,timezone:i}=e,s=`sched-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,o={id:s,email:r,scheduledFor:typeof n==="string"?n:n.toISOString(),timezone:i,status:"pending",createdAt:new Date().toISOString()};return await t.send({Bucket:a,Key:`scheduled/${s}.json`,Body:JSON.stringify(o,null,2),ContentType:"application/json"}),o}static async cancelScheduledEmail(e){let{s3Client:t,bucket:a,id:r}=e;try{let n=await t.send({Bucket:a,Key:`scheduled/${r}.json`}),i=JSON.parse(n.Body);if(i.status!=="pending")return!1;return i.status="cancelled",await t.send({Bucket:a,Key:`scheduled/${r}.json`,Body:JSON.stringify(i,null,2),ContentType:"application/json"}),!0}catch{return!1}}static async listScheduledEmails(e){let{s3Client:t,bucket:a,status:r}=e,n=await t.send({Bucket:a,Prefix:"scheduled/"}),i=[];for(let s of n.Contents||[]){if(!s.Key.endsWith(".json"))continue;try{let o=await t.send({Bucket:a,Key:s.Key}),c=JSON.parse(o.Body);if(!r||c.status===r)i.push(c)}catch{}}return i.sort((s,o)=>new Date(s.scheduledFor).getTime()-new Date(o.scheduledFor).getTime()),i}}class et{static TrackingPixelLambdaCode=`
|
|
4166
4166
|
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
4167
4167
|
|
|
4168
4168
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -4365,7 +4365,7 @@ catch (error) {
|
|
|
4365
4365
|
|
|
4366
4366
|
return { statusCode: 200 };
|
|
4367
4367
|
};
|
|
4368
|
-
`;static createAnalyticsTable(e){return{[`${e.slug}EmailAnalyticsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createTrackingPixelLambda(e){return{[`${e.slug}TrackingPixelLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-tracking-pixel`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:
|
|
4368
|
+
`;static createAnalyticsTable(e){return{[`${e.slug}EmailAnalyticsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createTrackingPixelLambda(e){return{[`${e.slug}TrackingPixelLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-tracking-pixel`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:et.TrackingPixelLambdaCode},Environment:{Variables:{ANALYTICS_TABLE:e.analyticsTable}}}}}}static createClickTrackingLambda(e){return{[`${e.slug}ClickTrackingLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-click-tracking`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:et.ClickTrackingLambdaCode},Environment:{Variables:{ANALYTICS_TABLE:e.analyticsTable}}}}}}static createSesEventProcessorLambda(e){return{[`${e.slug}SesEventProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-ses-event-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:et.SesEventProcessorCode},Environment:{Variables:{ANALYTICS_TABLE:e.analyticsTable}}}}}}static injectTracking(e){let{html:t,messageId:a,trackingDomain:r}=e,n=`<img src="https://${r}/track/open/${a}" width="1" height="1" style="display:none" alt="" />`,i=t.replace("</body>",`${n}</body>`);return i=i.replace(/href="(https?:\/\/[^"]+)"/g,(s,o)=>{let c=encodeURIComponent(o);return`href="https://${r}/track/click/${a}?url=${c}"`}),i}static calculateMetrics(e){let t=e.filter((c)=>c.sent).length,a=e.filter((c)=>c.delivered).length,r=e.filter((c)=>c.opened).length,n=e.filter((c)=>c.clicked).length,i=e.filter((c)=>c.bounced).length,s=e.filter((c)=>c.complained).length,o=e.filter((c)=>c.unsubscribed).length;return{period:new Date().toISOString(),sent:t,delivered:a,opened:r,clicked:n,bounced:i,complained:s,unsubscribed:o,deliveryRate:t>0?a/t*100:0,openRate:a>0?r/a*100:0,clickRate:r>0?n/r*100:0,bounceRate:t>0?i/t*100:0,complaintRate:a>0?s/a*100:0}}}class Re{static TemplateRendererCode=`
|
|
4369
4369
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
4370
4370
|
|
|
4371
4371
|
const s3 = new S3Client({});
|
|
@@ -4620,7 +4620,7 @@ The {{appName}} Team`,variables:["appName","userName","resetUrl","expiresIn"],ca
|
|
|
4620
4620
|
|
|
4621
4621
|
<p>Best regards,<br>The {{appName}} Team</p>
|
|
4622
4622
|
</body>
|
|
4623
|
-
</html>`,variables:["invoiceNumber","customerName","period","items","total","paymentUrl","appName"],category:"billing"}};static createTemplateBucket(e){return{[`${e.slug}EmailTemplateBucket`]:{Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-email-templates`,VersioningConfiguration:{Status:"Enabled"}}}}}static createTemplateRendererLambda(e){return{[`${e.slug}TemplateRendererLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-template-renderer`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:
|
|
4623
|
+
</html>`,variables:["invoiceNumber","customerName","period","items","total","paymentUrl","appName"],category:"billing"}};static createTemplateBucket(e){return{[`${e.slug}EmailTemplateBucket`]:{Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-email-templates`,VersioningConfiguration:{Status:"Enabled"}}}}}static createTemplateRendererLambda(e){return{[`${e.slug}TemplateRendererLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-template-renderer`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Re.TemplateRendererCode},Environment:{Variables:{TEMPLATE_BUCKET:e.templateBucket}}}}}}static render(e,t){if(!e||!t)return e;let a=e;return a=a.replace(/\{\{\s*([\w.]+)\s*\}\}/g,(r,n)=>{let i=Re.getNestedValue(t,n);return i!==void 0?String(i):r}),a=a.replace(/\{\{#if\s+([\w.]+)\}\}([\s\S]*?)\{\{\/if\}\}/g,(r,n,i)=>Re.getNestedValue(t,n)?i:""),a=a.replace(/\{\{#unless\s+([\w.]+)\}\}([\s\S]*?)\{\{\/unless\}\}/g,(r,n,i)=>!Re.getNestedValue(t,n)?i:""),a=a.replace(/\{\{#each\s+([\w.]+)\}\}([\s\S]*?)\{\{\/each\}\}/g,(r,n,i)=>{let s=Re.getNestedValue(t,n);if(!Array.isArray(s))return"";return s.map((o,c)=>{let l=i;if(l=l.replace(/\{\{this\}\}/g,String(o)),l=l.replace(/\{\{@index\}\}/g,String(c)),typeof o==="object")Object.entries(o).forEach(([u,m])=>{l=l.replace(new RegExp(`\\{\\{\\s*${u}\\s*\\}\\}`,"g"),String(m))});return l}).join("")}),a}static getNestedValue(e,t){return t.split(".").reduce((a,r)=>a?.[r],e)}static extractVariables(e){let t=new Set,a=e.matchAll(/\{\{\s*([\w.]+)\s*\}\}/g);for(let n of a)if(!n[1].startsWith("#")&&!n[1].startsWith("/")&&!n[1].startsWith("@"))t.add(n[1].split(".")[0]);let r=e.matchAll(/\{\{#(?:if|unless|each)\s+([\w.]+)\}\}/g);for(let n of r)t.add(n[1].split(".")[0]);return Array.from(t)}}class ta{static SharedMailboxLambdaCode=`
|
|
4624
4624
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
4625
4625
|
const { DynamoDBClient, GetItemCommand, PutItemCommand, QueryCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
4626
4626
|
|
|
@@ -4851,7 +4851,7 @@ function unmarshallMailbox(item) {
|
|
|
4851
4851
|
updatedAt: item.updatedAt.S,
|
|
4852
4852
|
};
|
|
4853
4853
|
}
|
|
4854
|
-
`;static createMailboxTable(e){return{[`${e.slug}SharedMailboxTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-shared-mailboxes`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"},{AttributeName:"type",AttributeType:"S"},{AttributeName:"mailboxId",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"type-index",KeySchema:[{AttributeName:"type",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}},{IndexName:"mailbox-index",KeySchema:[{AttributeName:"mailboxId",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}],Projection:{ProjectionType:"ALL"}}]}}}}static createSharedMailboxLambda(e){return{[`${e.slug}SharedMailboxLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-shared-mailbox`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:
|
|
4854
|
+
`;static createMailboxTable(e){return{[`${e.slug}SharedMailboxTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-shared-mailboxes`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"},{AttributeName:"type",AttributeType:"S"},{AttributeName:"mailboxId",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"type-index",KeySchema:[{AttributeName:"type",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}},{IndexName:"mailbox-index",KeySchema:[{AttributeName:"mailboxId",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}],Projection:{ProjectionType:"ALL"}}]}}}}static createSharedMailboxLambda(e){return{[`${e.slug}SharedMailboxLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-shared-mailbox`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:ta.SharedMailboxLambdaCode},Environment:{Variables:{EMAIL_BUCKET:e.emailBucket,MAILBOX_TABLE:e.mailboxTable}}}}}}static PermissionSets={owner:{read:!0,send:!0,delete:!0,manage:!0,assignTo:!0},admin:{read:!0,send:!0,delete:!0,manage:!0,assignTo:!0},member:{read:!0,send:!0,delete:!1,manage:!1,assignTo:!0},viewer:{read:!0,send:!1,delete:!1,manage:!1,assignTo:!1}}}class aa{static RuleProcessorCode=`
|
|
4855
4855
|
const { S3Client, GetObjectCommand, PutObjectCommand, CopyObjectCommand, DeleteObjectCommand } = require('@aws-sdk/client-s3');
|
|
4856
4856
|
const { DynamoDBClient, QueryCommand } = require('@aws-sdk/client-dynamodb');
|
|
4857
4857
|
const { LambdaClient, InvokeCommand } = require('@aws-sdk/client-lambda');
|
|
@@ -5164,7 +5164,7 @@ async function invokeLambda(functionName, metadata) {
|
|
|
5164
5164
|
Payload: JSON.stringify(metadata),
|
|
5165
5165
|
}));
|
|
5166
5166
|
}
|
|
5167
|
-
`;static createRulesTable(e){return{[`${e.slug}EmailRulesTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-email-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"mailbox",AttributeType:"S"},{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"mailbox",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}]}}}}static createRuleProcessorLambda(e){return{[`${e.slug}EmailRuleProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-rule-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:
|
|
5167
|
+
`;static createRulesTable(e){return{[`${e.slug}EmailRulesTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-email-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"mailbox",AttributeType:"S"},{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"mailbox",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}]}}}}static createRuleProcessorLambda(e){return{[`${e.slug}EmailRuleProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-email-rule-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:aa.RuleProcessorCode},Environment:{Variables:{EMAIL_BUCKET:e.emailBucket,RULES_TABLE:e.rulesTable}}}}}}static RuleTemplates={spamFilter:{name:"Spam Filter",conditions:[{field:"subject",operator:"regex",value:"(viagra|lottery|winner|prince|inheritance)",caseSensitive:!1}],conditionOperator:"or",actions:[{type:"move",params:{folder:"spam"}},{type:"mark-read",params:{}}]},autoLabel:{name:"Auto Label Invoices",conditions:[{field:"subject",operator:"contains",value:"invoice",caseSensitive:!1}],conditionOperator:"and",actions:[{type:"label",params:{label:"invoices"}}]},forwardUrgent:{name:"Forward Urgent",conditions:[{field:"subject",operator:"contains",value:"urgent",caseSensitive:!1}],conditionOperator:"and",actions:[{type:"forward",params:{to:"admin@example.com"}},{type:"label",params:{label:"urgent"}}]}}}var Co={};De(Co,{default:()=>vo,handler:()=>To});var To=`
|
|
5168
5168
|
const { S3Client, GetObjectCommand, PutObjectCommand, CopyObjectCommand } = require('@aws-sdk/client-s3');
|
|
5169
5169
|
const s3 = new S3Client({});
|
|
5170
5170
|
|
|
@@ -5322,7 +5322,7 @@ catch (error) {
|
|
|
5322
5322
|
|
|
5323
5323
|
return { statusCode: 200, body: 'OK' };
|
|
5324
5324
|
};
|
|
5325
|
-
`,
|
|
5325
|
+
`,vo=`
|
|
5326
5326
|
const { S3Client, GetObjectCommand, PutObjectCommand, CopyObjectCommand } = require('@aws-sdk/client-s3');
|
|
5327
5327
|
const s3 = new S3Client({});
|
|
5328
5328
|
|
|
@@ -5480,7 +5480,7 @@ catch (error) {
|
|
|
5480
5480
|
|
|
5481
5481
|
return { statusCode: 200, body: 'OK' };
|
|
5482
5482
|
};
|
|
5483
|
-
`,
|
|
5483
|
+
`,wo={};De(wo,{CallAnalytics:()=>na,CallRecording:()=>ra,Callbacks:()=>Tt,IVRBuilder:()=>Be});class ra{static RecordingProcessorCode=`
|
|
5484
5484
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
5485
5485
|
const { TranscribeClient, StartTranscriptionJobCommand } = require('@aws-sdk/client-transcribe');
|
|
5486
5486
|
const { DynamoDBClient, PutItemCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
@@ -5672,7 +5672,7 @@ else if (jobStatus === 'FAILED') {
|
|
|
5672
5672
|
|
|
5673
5673
|
return { statusCode: 200 };
|
|
5674
5674
|
};
|
|
5675
|
-
`;static createRecordingsTable(e){return{[`${e.slug}CallRecordingsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"},{AttributeName:"transcriptionJobName",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"job-index",KeySchema:[{AttributeName:"transcriptionJobName",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createRecordingProcessorLambda(e){return{[`${e.slug}RecordingProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-recording-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:
|
|
5675
|
+
`;static createRecordingsTable(e){return{[`${e.slug}CallRecordingsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"},{AttributeName:"transcriptionJobName",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"job-index",KeySchema:[{AttributeName:"transcriptionJobName",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createRecordingProcessorLambda(e){return{[`${e.slug}RecordingProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-recording-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:ra.RecordingProcessorCode},Environment:{Variables:{RECORDING_BUCKET:e.recordingBucket,RECORDINGS_TABLE:e.recordingsTable}}}}}}}class Be{nodes=[];connections=[];startNodeId="";static create(e){return new Be}start(){let e={id:this.generateId(),type:"start",position:{x:0,y:0},config:{}};return this.nodes.push(e),this.startNodeId=e.id,this}playPrompt(e,t){let a={id:this.generateId(),type:"play-prompt",position:{x:0,y:0},config:{text:e,textType:t?.ssml?"ssml":"text",voice:t?.voice||"Joanna"}};return this.nodes.push(a),this.connectToLast(a.id),this}getInput(e,t){let a={id:this.generateId(),type:"get-input",position:{x:0,y:0},config:{prompt:e,maxDigits:t?.maxDigits||1,timeout:t?.timeout||5,errorPrompt:t?.errorPrompt||"Sorry, I didn't get that."}};return this.nodes.push(a),this.connectToLast(a.id),this}menu(e,t){let a={id:this.generateId(),type:"menu",position:{x:0,y:0},config:{prompt:e,options:t}};return this.nodes.push(a),this.connectToLast(a.id),this}transferToQueue(e,t){let a={id:this.generateId(),type:"transfer-queue",position:{x:0,y:0},config:{queueArn:e,priority:t?.priority||5}};return this.nodes.push(a),this.connectToLast(a.id),this}transferToPhone(e){let t={id:this.generateId(),type:"transfer-phone",position:{x:0,y:0},config:{phoneNumber:e}};return this.nodes.push(t),this.connectToLast(t.id),this}invokeLambda(e,t){let a={id:this.generateId(),type:"invoke-lambda",position:{x:0,y:0},config:{functionArn:e,timeout:t?.timeout||8}};return this.nodes.push(a),this.connectToLast(a.id),this}setAttribute(e,t){let a={id:this.generateId(),type:"set-attribute",position:{x:0,y:0},config:{key:e,value:t}};return this.nodes.push(a),this.connectToLast(a.id),this}checkHours(e){let t={id:this.generateId(),type:"check-hours",position:{x:0,y:0},config:{hoursOfOperationArn:e}};return this.nodes.push(t),this.connectToLast(t.id),this}recordVoicemail(e){let t={id:this.generateId(),type:"record-voicemail",position:{x:0,y:0},config:{maxDuration:e?.maxDuration||120,greeting:e?.greeting||"Please leave a message after the beep.",beep:e?.beep!==!1}};return this.nodes.push(t),this.connectToLast(t.id),this}wait(e){let t={id:this.generateId(),type:"wait",position:{x:0,y:0},config:{seconds:e}};return this.nodes.push(t),this.connectToLast(t.id),this}disconnect(){let e={id:this.generateId(),type:"disconnect",position:{x:0,y:0},config:{}};return this.nodes.push(e),this.connectToLast(e.id),this}build(){return{id:this.generateId(),name:"IVR Flow",nodes:this.nodes,connections:this.connections,startNodeId:this.startNodeId,version:1,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()}}toContactFlow(){let e=[],t=new Map(this.nodes.map((r)=>[r.id,r]));for(let r of this.nodes){let n=this.nodeToAction(r,t);if(n)e.push(n)}let a={Version:"2019-10-30",StartAction:this.startNodeId,Actions:e};return JSON.stringify(a,null,2)}nodeToAction(e,t){let a=this.getNextNodeId(e.id),r={NextAction:a||"disconnect",Errors:[{NextAction:"disconnect"}]};switch(e.type){case"start":return null;case"play-prompt":return{Identifier:e.id,Type:"MessageParticipant",Parameters:{Text:e.config.text,TextType:e.config.textType},Transitions:r};case"get-input":return{Identifier:e.id,Type:"GetParticipantInput",Parameters:{Text:e.config.prompt,InputTimeLimitSeconds:e.config.timeout,MaxDigits:e.config.maxDigits},Transitions:{...r,Conditions:[]}};case"transfer-queue":return{Identifier:e.id,Type:"TransferToQueue",Parameters:{QueueId:e.config.queueArn},Transitions:r};case"transfer-phone":return{Identifier:e.id,Type:"TransferToPhoneNumber",Parameters:{PhoneNumber:e.config.phoneNumber},Transitions:r};case"invoke-lambda":return{Identifier:e.id,Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:e.config.functionArn,InvocationTimeLimitSeconds:e.config.timeout},Transitions:r};case"set-attribute":return{Identifier:e.id,Type:"UpdateContactAttributes",Parameters:{Attributes:{[e.config.key]:e.config.value}},Transitions:r};case"check-hours":return{Identifier:e.id,Type:"CheckHoursOfOperation",Parameters:{HoursOfOperationId:e.config.hoursOfOperationArn},Transitions:{NextAction:a,Conditions:[{NextAction:a,Condition:{Operator:"Equals",Operands:["True"]}}],Errors:[{NextAction:"disconnect"}]}};case"wait":return{Identifier:e.id,Type:"Wait",Parameters:{Seconds:e.config.seconds},Transitions:r};case"disconnect":return{Identifier:e.id,Type:"DisconnectParticipant",Parameters:{},Transitions:{}};default:return null}}connectToLast(e){if(this.nodes.length>1){let t=this.nodes[this.nodes.length-2];this.connections.push({id:this.generateId(),sourceNodeId:t.id,targetNodeId:e,sourcePort:"default"})}}getNextNodeId(e){return this.connections.find((t)=>t.sourceNodeId===e)?.targetNodeId||null}generateId(){return`node-${Date.now()}-${Math.random().toString(36).substr(2,9)}`}static Templates={basicSupport:()=>Be.create("Basic Support").start().playPrompt("Welcome to customer support.").menu("Press 1 for sales, 2 for support, or 3 to leave a message.",{"1":"sales","2":"support","3":"voicemail"}),afterHours:(e)=>Be.create("After Hours").start().playPrompt(e).recordVoicemail({greeting:"Please leave your name, number, and a brief message.",maxDuration:120}).playPrompt("Thank you for your message. Goodbye.").disconnect(),callbackRequest:(e)=>Be.create("Callback Request").start().playPrompt("All agents are currently busy.").getInput("Press 1 to request a callback, or 2 to wait.",{maxDigits:1}).invokeLambda(e).playPrompt("We will call you back shortly. Goodbye.").disconnect()}}class na{static MetricsAggregatorCode=`
|
|
5676
5676
|
const { DynamoDBClient, PutItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
|
|
5677
5677
|
|
|
5678
5678
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -5871,7 +5871,7 @@ catch (error) {
|
|
|
5871
5871
|
};
|
|
5872
5872
|
}
|
|
5873
5873
|
};
|
|
5874
|
-
`;static createMetricsTable(e){return{[`${e.slug}CallMetricsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createMetricsAggregatorLambda(e){return{[`${e.slug}CallMetricsAggregatorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-call-metrics-aggregator`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:
|
|
5874
|
+
`;static createMetricsTable(e){return{[`${e.slug}CallMetricsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createMetricsAggregatorLambda(e){return{[`${e.slug}CallMetricsAggregatorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-call-metrics-aggregator`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:na.MetricsAggregatorCode},Environment:{Variables:{CALL_LOG_TABLE:e.callLogTable,METRICS_TABLE:e.metricsTable}}}}}}static createMetricsSchedule(e){return{[`${e.slug}CallMetricsSchedule`]:{Type:"AWS::Events::Rule",Properties:{Name:`${e.slug}-call-metrics-schedule`,Description:"Aggregate call metrics hourly",ScheduleExpression:"rate(1 hour)",State:"ENABLED",Targets:[{Id:"MetricsAggregatorTarget",Arn:e.lambdaArn}]}}}}}class Tt{static CallbackRequestCode=`
|
|
5875
5875
|
const { DynamoDBClient, PutItemCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
5876
5876
|
const { ConnectClient, StartOutboundVoiceContactCommand } = require('@aws-sdk/client-connect');
|
|
5877
5877
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
@@ -6161,7 +6161,7 @@ catch (error) {
|
|
|
6161
6161
|
return { statusCode: 500, error: error.message };
|
|
6162
6162
|
}
|
|
6163
6163
|
};
|
|
6164
|
-
`;static createCallbacksTable(e){return{[`${e.slug}CallbacksTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCallbackRequestLambda(e){return{[`${e.slug}CallbackRequestLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-callback-request`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:
|
|
6164
|
+
`;static createCallbacksTable(e){return{[`${e.slug}CallbacksTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCallbackRequestLambda(e){return{[`${e.slug}CallbackRequestLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-callback-request`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Tt.CallbackRequestCode},Environment:{Variables:{CALLBACKS_TABLE:e.callbacksTable,NOTIFICATION_TOPIC_ARN:e.notificationTopicArn||""}}}}}}static createCallbackProcessorLambda(e){return{[`${e.slug}CallbackProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-callback-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:300,MemorySize:256,Code:{ZipFile:Tt.CallbackProcessorCode},Environment:{Variables:{CALLBACKS_TABLE:e.callbacksTable,CONNECT_INSTANCE_ID:e.connectInstanceId,CONTACT_FLOW_ID:e.contactFlowId,SOURCE_PHONE_NUMBER:e.sourcePhoneNumber,QUEUE_ID:e.queueId||""}}}}}}}var Eo={};De(Eo,{AbTesting:()=>Ce,LinkTracking:()=>la,MmsSupport:()=>oa,SmsAnalytics:()=>sa,SmsCampaigns:()=>ia,SmsChatbot:()=>ca});class ia{static CampaignManagerCode=`
|
|
6165
6165
|
const { DynamoDBClient, PutItemCommand, GetItemCommand, UpdateItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
|
|
6166
6166
|
|
|
6167
6167
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -6545,7 +6545,7 @@ function unmarshallCampaign(item) {
|
|
|
6545
6545
|
stats: JSON.parse(item.stats?.S || '{}'),
|
|
6546
6546
|
};
|
|
6547
6547
|
}
|
|
6548
|
-
`;static createCampaignsTable(e){return{[`${e.slug}SmsCampaignsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createCampaignManagerLambda(e){return{[`${e.slug}SmsCampaignManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-campaign-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:
|
|
6548
|
+
`;static createCampaignsTable(e){return{[`${e.slug}SmsCampaignsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createCampaignManagerLambda(e){return{[`${e.slug}SmsCampaignManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-campaign-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:ia.CampaignManagerCode},Environment:{Variables:{CAMPAIGNS_TABLE:e.campaignsTable}}}}}}}class sa{static AnalyticsAggregatorCode=`
|
|
6549
6549
|
const { DynamoDBClient, ScanCommand, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
6550
6550
|
|
|
6551
6551
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -6740,7 +6740,7 @@ catch (error) {
|
|
|
6740
6740
|
|
|
6741
6741
|
return { statusCode: 200 };
|
|
6742
6742
|
};
|
|
6743
|
-
`;static createAnalyticsTable(e){return{[`${e.slug}SmsAnalyticsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createDeliveryReportsTable(e){return{[`${e.slug}SmsDeliveryReportsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-delivery-reports`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createAnalyticsAggregatorLambda(e){return{[`${e.slug}SmsAnalyticsAggregatorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-analytics-aggregator`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:
|
|
6743
|
+
`;static createAnalyticsTable(e){return{[`${e.slug}SmsAnalyticsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createDeliveryReportsTable(e){return{[`${e.slug}SmsDeliveryReportsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-sms-delivery-reports`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createAnalyticsAggregatorLambda(e){return{[`${e.slug}SmsAnalyticsAggregatorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-sms-analytics-aggregator`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:sa.AnalyticsAggregatorCode},Environment:{Variables:{MESSAGE_LOG_TABLE:e.messageLogTable,ANALYTICS_TABLE:e.analyticsTable}}}}}}}class oa{static MmsSenderCode=`
|
|
6744
6744
|
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
6745
6745
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
6746
6746
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
@@ -6932,8 +6932,8 @@ async function sendFallbackSms(to, message) {
|
|
|
6932
6932
|
fallback: true,
|
|
6933
6933
|
};
|
|
6934
6934
|
}
|
|
6935
|
-
`;static createMediaBucket(e){return{[`${e.slug}MmsMediaBucket`]:{Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]},CorsConfiguration:{CorsRules:[{AllowedOrigins:["*"],AllowedMethods:["GET"],AllowedHeaders:["*"],MaxAge:3600}]}}}}}static createMmsSenderLambda(e){return{[`${e.slug}MmsSenderLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-mms-sender`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:512,Code:{ZipFile:
|
|
6936
|
-
`);static createSessionsTable(e){return{[`${e.slug}ChatbotSessionsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createRulesTable(e){return{[`${e.slug}ChatbotRulesTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createChatbotProcessorLambda(e){return{[`${e.slug}ChatbotProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-chatbot-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:
|
|
6935
|
+
`;static createMediaBucket(e){return{[`${e.slug}MmsMediaBucket`]:{Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]},CorsConfiguration:{CorsRules:[{AllowedOrigins:["*"],AllowedMethods:["GET"],AllowedHeaders:["*"],MaxAge:3600}]}}}}}static createMmsSenderLambda(e){return{[`${e.slug}MmsSenderLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-mms-sender`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:60,MemorySize:512,Code:{ZipFile:oa.MmsSenderCode},Environment:{Variables:{MEDIA_BUCKET:e.mediaBucket,MESSAGE_LOG_TABLE:e.messageLogTable,ORIGINATION_NUMBER:e.originationNumber||""}}}}}}static SupportedMediaTypes={image:["image/jpeg","image/png","image/gif"],video:["video/mp4","video/3gpp"],audio:["audio/mpeg","audio/wav"]};static MediaSizeLimits={image:1048576,video:5242880,audio:1048576}}class ca{static ChatbotProcessorCode=["const { DynamoDBClient, GetItemCommand, PutItemCommand, UpdateItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');","const { BedrockRuntimeClient, InvokeModelCommand } = require('@aws-sdk/client-bedrock-runtime');","const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');","","const dynamodb = new DynamoDBClient({});","const bedrock = new BedrockRuntimeClient({});","const sns = new SNSClient({});","","const SESSIONS_TABLE = process.env.SESSIONS_TABLE;","const RULES_TABLE = process.env.RULES_TABLE;","const CHATBOT_CONFIG = JSON.parse(process.env.CHATBOT_CONFIG || '{}');","","exports.handler = async (event) => {"," console.log('Chatbot event:', JSON.stringify(event, null, 2));"," for (const record of event.Records) {"," try {"," const message = JSON.parse(record.Sns?.Message || record.body || '{}');"," const { originationNumber, messageBody } = message;"," if (!originationNumber || !messageBody) continue;"," const response = await processMessage(originationNumber, messageBody.trim());"," await sendResponse(originationNumber, response);"," } catch (error) {"," console.error('Error:', error);"," }"," }"," return { statusCode: 200 };","};","","async function processMessage(phoneNumber, message) {"," const rules = await getRules();"," const lowerMessage = message.toLowerCase();"," for (const rule of rules) {"," for (const pattern of rule.patterns) {"," if (new RegExp(pattern, 'i').test(lowerMessage)) {"," return rule.response;"," }"," }"," }"," return CHATBOT_CONFIG.fallbackMessage || 'Sorry, I did not understand. Please try again.';","}","","async function getRules() {"," const result = await dynamodb.send(new ScanCommand({ TableName: RULES_TABLE }));"," return (result.Items || []).map(item => ({"," patterns: JSON.parse(item.patterns?.S || '[]'),"," response: item.response?.S || '',"," })).sort((a, b) => (a.priority || 0) - (b.priority || 0));","}","","async function sendResponse(phoneNumber, message) {"," await sns.send(new PublishCommand({"," PhoneNumber: phoneNumber,"," Message: message.substring(0, 1600),"," MessageAttributes: {"," 'AWS.SNS.SMS.SMSType': { DataType: 'String', StringValue: 'Transactional' },"," },"," }));","}"].join(`
|
|
6936
|
+
`);static createSessionsTable(e){return{[`${e.slug}ChatbotSessionsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createRulesTable(e){return{[`${e.slug}ChatbotRulesTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createChatbotProcessorLambda(e){return{[`${e.slug}ChatbotProcessorLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-chatbot-processor`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:ca.ChatbotProcessorCode},Environment:{Variables:{SESSIONS_TABLE:e.sessionsTable,RULES_TABLE:e.rulesTable,CHATBOT_CONFIG:JSON.stringify(e.chatbotConfig),ORIGINATION_NUMBER:e.originationNumber||""}}}}}}static DefaultRules=[{id:"greeting",priority:1,patterns:["^(hi|hello|hey|howdy)$","^good (morning|afternoon|evening)"],response:"Hello! How can I help you today?"},{id:"help",priority:2,patterns:["^help$","what can you do","how does this work"],response:"I can help with: 1) Account info 2) Support 3) Hours. Reply with a number."},{id:"hours",priority:3,patterns:["hours","open","when are you"],response:"We are open Mon-Fri 9am-5pm EST. Closed weekends."},{id:"thanks",priority:4,patterns:["^(thanks|thank you|thx)"],response:"You're welcome! Is there anything else I can help with?"},{id:"bye",priority:5,patterns:["^(bye|goodbye|quit|exit|stop)$"],response:"Goodbye! Text us anytime if you need help.",action:"end"}]}class la{static LinkShortenerCode=`
|
|
6937
6937
|
const { DynamoDBClient, PutItemCommand, GetItemCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
6938
6938
|
const crypto = require('crypto');
|
|
6939
6939
|
|
|
@@ -7067,7 +7067,7 @@ function generateShortId() {
|
|
|
7067
7067
|
}
|
|
7068
7068
|
return id;
|
|
7069
7069
|
}
|
|
7070
|
-
`;static createLinksTable(e){return{[`${e.slug}ShortLinksTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createLinkShortenerLambda(e){return{[`${e.slug}LinkShortenerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-link-shortener`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:
|
|
7070
|
+
`;static createLinksTable(e){return{[`${e.slug}ShortLinksTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createLinkShortenerLambda(e){return{[`${e.slug}LinkShortenerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-link-shortener`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:10,MemorySize:128,Code:{ZipFile:la.LinkShortenerCode},Environment:{Variables:{LINKS_TABLE:e.linksTable,SHORT_DOMAIN:e.shortDomain||""}}}}}}static shortenUrlsInMessage(e,t,a){let r=/(https?:\/\/[^\s]+)/g,n=[],i=0;return{message:e.replace(r,(s)=>{let o=`${a}-${i++}`,c=`https://${t}/l/${o}`;return n.push({original:s,short:c,id:o}),c}),links:n}}}class Ce{static AbTestManagerCode=`
|
|
7071
7071
|
const { DynamoDBClient, PutItemCommand, GetItemCommand, UpdateItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
|
|
7072
7072
|
|
|
7073
7073
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -7261,7 +7261,7 @@ function unmarshallTest(item) {
|
|
|
7261
7261
|
|
|
7262
7262
|
return test;
|
|
7263
7263
|
}
|
|
7264
|
-
`;static createAbTestsTable(e){return{[`${e.slug}AbTestsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createAbTestManagerLambda(e){return{[`${e.slug}AbTestManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-ab-test-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Ae.AbTestManagerCode},Environment:{Variables:{AB_TESTS_TABLE:e.abTestsTable}}}}}}static selectVariant(e,t){let a=Ae.hashString(t+e.id)%100,r=0;for(let n=0;n<e.variants.length;n++)if(r+=e.trafficSplit[n],a<r)return e.variants[n];return e.variants[e.variants.length-1]}static determineWinner(e){if(e.variants.length===0)return null;let t=e.winningCriteria,a=e.variants[0],r=Ae.getMetricValue(a,t);for(let n of e.variants.slice(1)){let i=Ae.getMetricValue(n,t);if(i>r)r=i,a=n}return a}static calculateSignificance(e,t,a){let r=e.stats.sent,n=t.stats.sent;if(r<30||n<30)return 0;let i=Ae.getMetricValue(e,a)/100,s=Ae.getMetricValue(t,a)/100,o=(i*r+s*n)/(r+n),c=Math.sqrt(o*(1-o)*(1/r+1/n));if(c===0)return 0;let l=Math.abs(i-s)/c;if(l>=2.576)return 99;if(l>=1.96)return 95;if(l>=1.645)return 90;if(l>=1.28)return 80;return Math.round(l*30)}static getMetricValue(e,t){switch(t){case"delivery_rate":return e.stats.deliveryRate;case"click_rate":return e.stats.clickRate;case"reply_rate":return e.stats.replyRate;case"conversion_rate":return e.stats.conversionRate;default:return e.stats.deliveryRate}}static hashString(e){let t=0;for(let a=0;a<e.length;a++){let r=e.charCodeAt(a);t=(t<<5)-t+r,t=t&t}return Math.abs(t)}}class nn{queues=new Map;messageGroups=new Map;deduplicationConfigs=new Map;messages=new Map;queueCounter=0;groupCounter=0;deduplicationCounter=0;messageCounter=0;sequenceCounter=0;createFIFOQueue(e){let t=`fifo-queue-${Date.now()}-${this.queueCounter++}`,a=e.name.endsWith(".fifo")?e.name:`${e.name}.fifo`,{name:r,...n}=e,i={id:t,name:a,queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${a}`,...n};return this.queues.set(t,i),this.createDeduplicationConfig({queueId:t,contentBasedDeduplication:e.contentBasedDeduplication,deduplicationInterval:300}),i}createHighThroughputFIFO(e){return this.createFIFOQueue({name:e.name,contentBasedDeduplication:e.contentBasedDeduplication??!0,deduplicationScope:"messageGroup",fifoThroughputLimit:"perMessageGroupId",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createStandardFIFO(e){return this.createFIFOQueue({name:e.name,contentBasedDeduplication:e.contentBasedDeduplication??!1,deduplicationScope:"queue",fifoThroughputLimit:"perQueue",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createDeduplicationConfig(e){let t={id:`dedup-${Date.now()}-${this.deduplicationCounter++}`,deduplicationHashes:new Map,...e};return this.deduplicationConfigs.set(e.queueId,t),t}sendMessage(e){let t=this.queues.get(e.queueId);if(!t)throw Error(`Queue not found: ${e.queueId}`);let a=this.deduplicationConfigs.get(e.queueId);if(a){let s=e.messageDeduplicationId||(t.contentBasedDeduplication?this.generateHash(e.messageBody):void 0);if(s&&this.isDuplicate(a,s))return null;if(s)a.deduplicationHashes.set(s,new Date)}let r=`msg-${Date.now()}-${this.messageCounter++}`,n=this.generateSequenceNumber(),i={id:r,messageId:r,messageGroupId:e.messageGroupId,messageDeduplicationId:e.messageDeduplicationId,body:e.messageBody,attributes:e.messageAttributes||{},sentTimestamp:new Date,sequenceNumber:n};return this.messages.set(r,i),this.updateMessageGroup(e.queueId,e.messageGroupId),i}isDuplicate(e,t){let a=e.deduplicationHashes.get(t);if(!a)return!1;if((Date.now()-a.getTime())/1000>e.deduplicationInterval)return e.deduplicationHashes.delete(t),!1;return!0}generateHash(e){let t=0;for(let a=0;a<e.length;a++){let r=e.charCodeAt(a);t=(t<<5)-t+r,t=t&t}return Math.abs(t).toString(36)}generateSequenceNumber(){return`${Date.now()}${this.sequenceCounter++}`.padStart(20,"0")}updateMessageGroup(e,t){let a=`${e}-${t}`,r=this.messageGroups.get(a);if(!r)r={id:`group-${Date.now()}-${this.groupCounter++}`,messageGroupId:t,queueId:e,messagesInFlight:0},this.messageGroups.set(a,r);r.messagesInFlight++,r.lastMessageTimestamp=new Date}getMessageGroups(e){return Array.from(this.messageGroups.values()).filter((t)=>t.queueId===e)}getQueue(e){return this.queues.get(e)}listQueues(){return Array.from(this.queues.values())}getMessages(e,t){let a=Array.from(this.messages.values());if(t)a=a.filter((r)=>r.messageGroupId===t);return a.sort((r,n)=>r.sequenceNumber.localeCompare(n.sequenceNumber))}generateFIFOQueueCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:e.name,FifoQueue:!0,ContentBasedDeduplication:e.contentBasedDeduplication,DeduplicationScope:e.deduplicationScope,FifoThroughputLimit:e.fifoThroughputLimit,MessageRetentionPeriod:e.messageRetentionPeriod,VisibilityTimeout:e.visibilityTimeout,ReceiveMessageWaitTimeSeconds:e.receiveMessageWaitTime,...e.deadLetterTargetArn&&{RedrivePolicy:{deadLetterTargetArn:e.deadLetterTargetArn,maxReceiveCount:e.maxReceiveCount||3}}}}}clear(){this.queues.clear(),this.messageGroups.clear(),this.deduplicationConfigs.clear(),this.messages.clear(),this.queueCounter=0,this.groupCounter=0,this.deduplicationCounter=0,this.messageCounter=0,this.sequenceCounter=0}}var xm=new nn;class sn{monitors=new Map;metrics=new Map;alerts=new Map;reprocessJobs=new Map;monitorCounter=0;metricsCounter=0;alertCounter=0;jobCounter=0;createDLQMonitor(e){let t=`dlq-monitor-${Date.now()}-${this.monitorCounter++}`,a={id:t,...e};return this.monitors.set(t,a),a}createAutomatedMonitor(e){return this.createDLQMonitor({name:e.name,queueUrl:e.queueUrl,sourceQueues:e.sourceQueues,maxReceiveCount:3,alarmThreshold:10,autoReprocess:!0,reprocessStrategy:"scheduled",notificationTopicArn:e.notificationTopicArn})}collectMetrics(e){let t={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:e,timestamp:new Date,approximateNumberOfMessages:Math.floor(Math.random()*100),approximateAgeOfOldestMessage:Math.floor(Math.random()*86400),messagesReceived:Math.floor(Math.random()*50),messagesDeleted:Math.floor(Math.random()*30),messagesReprocessed:Math.floor(Math.random()*20)},a=this.metrics.get(e)||[];return a.push(t),this.metrics.set(e,a),this.checkForAlerts(e,t),t}checkForAlerts(e,t){let a=Array.from(this.monitors.values()).find((n)=>n.queueUrl===e);if(!a)return;if(t.approximateNumberOfMessages>=a.alarmThreshold)this.createAlert({monitorId:a.id,alertType:"threshold_exceeded",severity:"high",message:`DLQ ${a.name} has ${t.approximateNumberOfMessages} messages (threshold: ${a.alarmThreshold})`});let r=3600;if(t.approximateAgeOfOldestMessage>r)this.createAlert({monitorId:a.id,alertType:"old_message",severity:"medium",message:`DLQ ${a.name} has messages older than ${r} seconds`})}createAlert(e){let t=`alert-${Date.now()}-${this.alertCounter++}`,a={id:t,timestamp:new Date,acknowledged:!1,...e};return this.alerts.set(t,a),a}acknowledgeAlert(e){let t=this.alerts.get(e);if(!t)throw Error(`Alert not found: ${e}`);return t.acknowledged=!0,t}createReprocessJob(e){let t=`reprocess-${Date.now()}-${this.jobCounter++}`,a={id:t,queueUrl:e.queueUrl,messageId:e.messageId,attempts:0,status:"pending"};return this.reprocessJobs.set(t,a),a}async executeReprocessJob(e){let t=this.reprocessJobs.get(e);if(!t)throw Error(`Reprocess job not found: ${e}`);t.status="processing",t.startedAt=new Date,t.attempts++,await new Promise((r)=>setTimeout(r,100));let a=Math.random()>0.3;if(t.status=a?"success":"failed",t.completedAt=new Date,!a)t.error="Reprocessing failed - original error still present";return t}async batchReprocess(e){let t=[];for(let a=0;a<e.maxMessages;a++){let r=this.createReprocessJob({queueUrl:e.queueUrl,messageId:`msg-${a}`});await this.executeReprocessJob(r.id),t.push(r)}return t}getDLQStatistics(e,t=24){let a=new Date(Date.now()-t*60*60*1000),r=(this.metrics.get(e)||[]).filter((u)=>u.timestamp>=a);if(r.length===0)return{totalMessages:0,avgAge:0,messagesReceived:0,messagesDeleted:0,messagesReprocessed:0,successRate:0};let n=r[r.length-1],i=r.reduce((u,m)=>u+m.messagesReceived,0),s=r.reduce((u,m)=>u+m.messagesDeleted,0),o=r.reduce((u,m)=>u+m.messagesReprocessed,0),c=r.reduce((u,m)=>u+m.approximateAgeOfOldestMessage,0)/r.length,l=o>0?s/o*100:0;return{totalMessages:n.approximateNumberOfMessages,avgAge:c,messagesReceived:i,messagesDeleted:s,messagesReprocessed:o,successRate:l}}getMonitor(e){return this.monitors.get(e)}listMonitors(){return Array.from(this.monitors.values())}getAlerts(e,t){let a=Array.from(this.alerts.values());if(e)a=a.filter((r)=>r.monitorId===e);if(t!==void 0)a=a.filter((r)=>r.acknowledged===t);return a.sort((r,n)=>n.timestamp.getTime()-r.timestamp.getTime())}getReprocessJobs(e){let t=Array.from(this.reprocessJobs.values());if(e)t=t.filter((a)=>a.queueUrl===e);return t}generateDLQAlarmCF(e){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e.name}-messages-alarm`,AlarmDescription:`Alert when DLQ ${e.name} exceeds threshold`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:1,Threshold:e.alarmThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:e.queueUrl.split("/").pop()}],...e.notificationTopicArn&&{AlarmActions:[e.notificationTopicArn]}}}}clear(){this.monitors.clear(),this.metrics.clear(),this.alerts.clear(),this.reprocessJobs.clear(),this.monitorCounter=0,this.metricsCounter=0,this.alertCounter=0,this.jobCounter=0}}var Om=new sn;class on{configs=new Map;jobs=new Map;metrics=new Map;configCounter=0;jobCounter=0;metricsCounter=0;createBatchConfig(e){let t=`batch-config-${Date.now()}-${this.configCounter++}`,a={id:t,...e};return this.configs.set(t,a),a}createHighThroughputConfig(e){return this.createBatchConfig({queueUrl:e.queueUrl,batchSize:10,maxWaitTime:100,parallelProcessors:10,retryAttempts:3,visibilityTimeout:30})}createLowLatencyConfig(e){return this.createBatchConfig({queueUrl:e.queueUrl,batchSize:1,maxWaitTime:0,parallelProcessors:5,retryAttempts:2,visibilityTimeout:10})}createBatchJob(e){let t=`batch-job-${Date.now()}-${this.jobCounter++}`;if(!this.configs.get(e.configId))throw Error(`Batch config not found: ${e.configId}`);let a=[];for(let n=0;n<e.messageCount;n++)a.push({id:`msg-${t}-${n}`,messageId:`${t}-${n}`,body:`Message ${n}`,receiptHandle:`receipt-${t}-${n}`,attributes:{},status:"pending"});let r={id:t,configId:e.configId,messages:a,status:"pending",processedCount:0,failedCount:0};return this.jobs.set(t,r),r}async processBatchJob(e){let t=this.jobs.get(e);if(!t)throw Error(`Batch job not found: ${e}`);let a=this.configs.get(t.configId);if(!a)throw Error(`Batch config not found: ${t.configId}`);t.status="processing",t.startedAt=new Date;let r=this.chunkArray(t.messages,a.batchSize);for(let n of r)await this.processBatch(n,a);return t.processedCount=t.messages.filter((n)=>n.status==="success").length,t.failedCount=t.messages.filter((n)=>n.status==="failed").length,t.status=t.failedCount===0?"completed":"failed",t.completedAt=new Date,this.collectProcessorMetrics(a.id,t),t}async processBatch(e,t){let a=e.map((r)=>this.processMessage(r,t));await Promise.all(a)}async processMessage(e,t){e.status="processing";let a=Date.now();await new Promise((n)=>setTimeout(n,Math.random()*100));let r=Date.now()-a;if(e.processingTime=r,Math.random()>0.1)e.status="success";else e.status="failed",e.error="Processing error"}chunkArray(e,t){let a=[];for(let r=0;r<e.length;r+=t)a.push(e.slice(r,r+t));return a}collectProcessorMetrics(e,t){let a=`metrics-${Date.now()}-${this.metricsCounter++}`,r=t.messages.filter((u)=>u.status==="success").map((u)=>u.processingTime||0).filter((u)=>u>0),n=r.length>0?r.reduce((u,m)=>u+m,0)/r.length:0,i=t.completedAt&&t.startedAt?(t.completedAt.getTime()-t.startedAt.getTime())/1000:1,s=t.processedCount/i,o=t.messages.length>0?t.failedCount/t.messages.length*100:0,c={id:a,configId:e,timestamp:new Date,messagesProcessed:t.processedCount,averageProcessingTime:n,throughput:s,errorRate:o},l=this.metrics.get(e)||[];l.push(c),this.metrics.set(e,l)}getBatchStatistics(e){let t=this.metrics.get(e)||[];if(t.length===0)return{totalJobsProcessed:0,totalMessagesProcessed:0,averageThroughput:0,averageErrorRate:0,averageProcessingTime:0};let a=t.reduce((s,o)=>s+o.messagesProcessed,0),r=t.reduce((s,o)=>s+o.throughput,0)/t.length,n=t.reduce((s,o)=>s+o.errorRate,0)/t.length,i=t.reduce((s,o)=>s+o.averageProcessingTime,0)/t.length;return{totalJobsProcessed:t.length,totalMessagesProcessed:a,averageThroughput:r,averageErrorRate:n,averageProcessingTime:i}}optimizeBatchConfig(e){let t=this.configs.get(e);if(!t)throw Error(`Batch config not found: ${e}`);let a=this.getBatchStatistics(e);if(a.averageErrorRate<5&&t.batchSize<10)t.batchSize=Math.min(10,t.batchSize+1);if(a.averageErrorRate>20&&t.batchSize>1)t.batchSize=Math.max(1,t.batchSize-1);if(a.averageThroughput<5&&t.parallelProcessors<20)t.parallelProcessors++;return t}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getJob(e){return this.jobs.get(e)}listJobs(e){let t=Array.from(this.jobs.values());if(e)t=t.filter((a)=>a.configId===e);return t}generateBatchProcessorCF(e){return{Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:`arn:aws:sqs:us-east-1:123456789012:${e.queueUrl.split("/").pop()}`,FunctionName:"batch-processor-function",BatchSize:e.batchSize,MaximumBatchingWindowInSeconds:e.maxWaitTime/1000,FunctionResponseTypes:["ReportBatchItemFailures"]}}}clear(){this.configs.clear(),this.jobs.clear(),this.metrics.clear(),this.configCounter=0,this.jobCounter=0,this.metricsCounter=0}}var Wm=new on;class cn{queues=new Map;retentionPolicies=new Map;delayQueues=new Map;purgeOperations=new Map;metrics=new Map;queueCounter=0;retentionCounter=0;delayCounter=0;purgeCounter=0;metricsCounter=0;createQueue(e){let t=`queue-${Date.now()}-${this.queueCounter++}`,a={id:t,purgeInProgress:!1,...e};return this.queues.set(t,a),a}createStandardQueue(e){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${e.queueName}`,queueName:e.queueName,messageRetentionPeriod:(e.messageRetentionDays||4)*24*60*60,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:0})}createLongPollingQueue(e){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${e.queueName}`,queueName:e.queueName,messageRetentionPeriod:345600,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:e.waitTimeSeconds||20})}createRetentionPolicy(e){let t=`retention-${Date.now()}-${this.retentionCounter++}`,a={id:t,...e};this.retentionPolicies.set(t,a);let r=this.queues.get(e.queueId);if(r)r.messageRetentionPeriod=e.retentionPeriod;return a}createShortRetentionPolicy(e){return this.createRetentionPolicy({queueId:e.queueId,retentionPeriod:e.retentionHours*60*60,autoCleanup:!0,archiveExpiredMessages:!1})}createArchivalRetentionPolicy(e){return this.createRetentionPolicy({queueId:e.queueId,retentionPeriod:e.retentionDays*24*60*60,autoCleanup:!0,cleanupSchedule:"cron(0 0 * * ? *)",archiveExpiredMessages:!0,archiveS3Bucket:e.s3Bucket})}createDelayQueue(e){let t=`delay-${Date.now()}-${this.delayCounter++}`,a={id:t,...e};this.delayQueues.set(t,a);let r=Array.from(this.queues.values()).find((n)=>n.queueUrl===e.queueUrl);if(r)r.delaySeconds=e.defaultDelay;return a}createScheduledDelayQueue(e){return this.createDelayQueue({queueUrl:e.queueUrl,defaultDelay:e.delayMinutes*60,perMessageDelay:!1,maxDelay:900})}async purgeQueue(e){let t=this.queues.get(e);if(!t)throw Error(`Queue not found: ${e}`);if(t.purgeInProgress)throw Error("Purge already in progress for this queue");let a=`purge-${Date.now()}-${this.purgeCounter++}`,r={id:a,queueUrl:t.queueUrl,status:"in_progress",startedAt:new Date};return this.purgeOperations.set(a,r),t.purgeInProgress=!0,setTimeout(()=>{r.status="completed",r.completedAt=new Date,r.messagesPurged=Math.floor(Math.random()*1000),t.purgeInProgress=!1},100),r}collectQueueMetrics(e){let t={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:e,timestamp:new Date,approximateNumberOfMessages:Math.floor(Math.random()*1000),approximateNumberOfMessagesNotVisible:Math.floor(Math.random()*100),approximateNumberOfMessagesDelayed:Math.floor(Math.random()*50),oldestMessageAge:Math.floor(Math.random()*86400)},a=this.metrics.get(e)||[];return a.push(t),this.metrics.set(e,a),t}getQueueHealth(e){let t=this.metrics.get(e)||[];if(t.length===0)return{status:"healthy",issues:[],recommendations:[]};let a=t[t.length-1],r=[],n=[],i="healthy";if(a.approximateNumberOfMessages>1e4)i="critical",r.push("Large message backlog detected"),n.push("Increase consumer capacity");else if(a.approximateNumberOfMessages>1000)i="warning",r.push("Growing message backlog"),n.push("Monitor consumer performance");if(a.oldestMessageAge&&a.oldestMessageAge>3600){if(i!=="critical")i="warning";r.push("Old messages in queue"),n.push("Review message processing")}if(a.approximateNumberOfMessagesDelayed>100){if(i!=="critical")i="warning";r.push("High number of delayed messages")}return{status:i,issues:r,recommendations:n}}getQueue(e){return this.queues.get(e)}listQueues(){return Array.from(this.queues.values())}getRetentionPolicy(e){return this.retentionPolicies.get(e)}listRetentionPolicies(){return Array.from(this.retentionPolicies.values())}getPurgeOperations(e){let t=Array.from(this.purgeOperations.values());if(e)t=t.filter((a)=>a.queueUrl===e);return t}generateQueueCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:e.queueName,MessageRetentionPeriod:e.messageRetentionPeriod,DelaySeconds:e.delaySeconds,MaximumMessageSize:e.maximumMessageSize,ReceiveMessageWaitTimeSeconds:e.receiveMessageWaitTime}}}generateCleanupRuleCF(e){return{Type:"AWS::Events::Rule",Properties:{Name:`${e.id}-cleanup`,Description:"Automated queue cleanup",ScheduleExpression:e.cleanupSchedule||"cron(0 0 * * ? *)",State:"ENABLED",Targets:[{Arn:"arn:aws:lambda:us-east-1:123456789012:function:queue-cleanup",Id:e.id,Input:JSON.stringify({queueId:e.queueId,archiveBucket:e.archiveS3Bucket})}]}}}clear(){this.queues.clear(),this.retentionPolicies.clear(),this.delayQueues.clear(),this.purgeOperations.clear(),this.metrics.clear(),this.queueCounter=0,this.retentionCounter=0,this.delayCounter=0,this.purgeCounter=0,this.metricsCounter=0}}var _m=new cn,Po=(()=>{let e=[];for(let t=0;t<256;t++){let a=t;for(let r=0;r<8;r++)a=a&1?3988292384^a>>>1:a>>>1;e[t]=a>>>0}return e})();function Io(e){let t=4294967295;for(let a=0;a<e.length;a++)t=Po[(t^e[a])&255]^t>>>8;return(t^4294967295)>>>0}function Ro(e){if(typeof e==="string")return Buffer.from(e,"utf-8");if(Buffer.isBuffer(e))return e;return Buffer.from(e)}function No(e){let t=Math.max(1980,e.getFullYear()),a=(e.getHours()<<11|e.getMinutes()<<5|e.getSeconds()>>1)&65535,r=(t-1980<<9|e.getMonth()+1<<5|e.getDate())&65535;return{time:a,date:r}}function at(e){let t=[],a=[],r=0;for(let s of e){let o=Ro(s.data),c=Eo(o),l=Io(o),u=Buffer.from(s.name.replace(/\\/g,"/"),"utf-8"),{time:m,date:p}=No(s.date??new Date(0)),g=s.mode??420,h=Buffer.alloc(30+u.length);h.writeUInt32LE(67324752,0),h.writeUInt16LE(20,4),h.writeUInt16LE(0,6),h.writeUInt16LE(8,8),h.writeUInt16LE(m,10),h.writeUInt16LE(p,12),h.writeUInt32LE(l,14),h.writeUInt32LE(c.length,18),h.writeUInt32LE(o.length,22),h.writeUInt16LE(u.length,26),h.writeUInt16LE(0,28),u.copy(h,30);let y=Buffer.alloc(46+u.length);y.writeUInt32LE(33639248,0),y.writeUInt16LE(798,4),y.writeUInt16LE(20,6),y.writeUInt16LE(0,8),y.writeUInt16LE(8,10),y.writeUInt16LE(m,12),y.writeUInt16LE(p,14),y.writeUInt32LE(l,16),y.writeUInt32LE(c.length,20),y.writeUInt32LE(o.length,24),y.writeUInt16LE(u.length,28),y.writeUInt16LE(0,30),y.writeUInt16LE(0,32),y.writeUInt16LE(0,34),y.writeUInt16LE(0,36),y.writeUInt32LE((g&65535)<<16,38),y.writeUInt32LE(r,42),u.copy(y,46),t.push(h,c),a.push(y),r+=h.length+c.length}let n=Buffer.concat(a),i=Buffer.alloc(22);return i.writeUInt32LE(101010256,0),i.writeUInt16LE(0,4),i.writeUInt16LE(0,6),i.writeUInt16LE(e.length,8),i.writeUInt16LE(e.length,10),i.writeUInt32LE(n.length,12),i.writeUInt32LE(r,16),i.writeUInt16LE(0,20),Buffer.concat([...t,n,i])}function Do(e){let t=e.adapterImport??"./adapter",a=e.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
|
|
7264
|
+
`;static createAbTestsTable(e){return{[`${e.slug}AbTestsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createAbTestManagerLambda(e){return{[`${e.slug}AbTestManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-ab-test-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Ce.AbTestManagerCode},Environment:{Variables:{AB_TESTS_TABLE:e.abTestsTable}}}}}}static selectVariant(e,t){let a=Ce.hashString(t+e.id)%100,r=0;for(let n=0;n<e.variants.length;n++)if(r+=e.trafficSplit[n],a<r)return e.variants[n];return e.variants[e.variants.length-1]}static determineWinner(e){if(e.variants.length===0)return null;let t=e.winningCriteria,a=e.variants[0],r=Ce.getMetricValue(a,t);for(let n of e.variants.slice(1)){let i=Ce.getMetricValue(n,t);if(i>r)r=i,a=n}return a}static calculateSignificance(e,t,a){let r=e.stats.sent,n=t.stats.sent;if(r<30||n<30)return 0;let i=Ce.getMetricValue(e,a)/100,s=Ce.getMetricValue(t,a)/100,o=(i*r+s*n)/(r+n),c=Math.sqrt(o*(1-o)*(1/r+1/n));if(c===0)return 0;let l=Math.abs(i-s)/c;if(l>=2.576)return 99;if(l>=1.96)return 95;if(l>=1.645)return 90;if(l>=1.28)return 80;return Math.round(l*30)}static getMetricValue(e,t){switch(t){case"delivery_rate":return e.stats.deliveryRate;case"click_rate":return e.stats.clickRate;case"reply_rate":return e.stats.replyRate;case"conversion_rate":return e.stats.conversionRate;default:return e.stats.deliveryRate}}static hashString(e){let t=0;for(let a=0;a<e.length;a++){let r=e.charCodeAt(a);t=(t<<5)-t+r,t=t&t}return Math.abs(t)}}class sn{queues=new Map;messageGroups=new Map;deduplicationConfigs=new Map;messages=new Map;queueCounter=0;groupCounter=0;deduplicationCounter=0;messageCounter=0;sequenceCounter=0;createFIFOQueue(e){let t=`fifo-queue-${Date.now()}-${this.queueCounter++}`,a=e.name.endsWith(".fifo")?e.name:`${e.name}.fifo`,{name:r,...n}=e,i={id:t,name:a,queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${a}`,...n};return this.queues.set(t,i),this.createDeduplicationConfig({queueId:t,contentBasedDeduplication:e.contentBasedDeduplication,deduplicationInterval:300}),i}createHighThroughputFIFO(e){return this.createFIFOQueue({name:e.name,contentBasedDeduplication:e.contentBasedDeduplication??!0,deduplicationScope:"messageGroup",fifoThroughputLimit:"perMessageGroupId",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createStandardFIFO(e){return this.createFIFOQueue({name:e.name,contentBasedDeduplication:e.contentBasedDeduplication??!1,deduplicationScope:"queue",fifoThroughputLimit:"perQueue",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createDeduplicationConfig(e){let t={id:`dedup-${Date.now()}-${this.deduplicationCounter++}`,deduplicationHashes:new Map,...e};return this.deduplicationConfigs.set(e.queueId,t),t}sendMessage(e){let t=this.queues.get(e.queueId);if(!t)throw Error(`Queue not found: ${e.queueId}`);let a=this.deduplicationConfigs.get(e.queueId);if(a){let s=e.messageDeduplicationId||(t.contentBasedDeduplication?this.generateHash(e.messageBody):void 0);if(s&&this.isDuplicate(a,s))return null;if(s)a.deduplicationHashes.set(s,new Date)}let r=`msg-${Date.now()}-${this.messageCounter++}`,n=this.generateSequenceNumber(),i={id:r,messageId:r,messageGroupId:e.messageGroupId,messageDeduplicationId:e.messageDeduplicationId,body:e.messageBody,attributes:e.messageAttributes||{},sentTimestamp:new Date,sequenceNumber:n};return this.messages.set(r,i),this.updateMessageGroup(e.queueId,e.messageGroupId),i}isDuplicate(e,t){let a=e.deduplicationHashes.get(t);if(!a)return!1;if((Date.now()-a.getTime())/1000>e.deduplicationInterval)return e.deduplicationHashes.delete(t),!1;return!0}generateHash(e){let t=0;for(let a=0;a<e.length;a++){let r=e.charCodeAt(a);t=(t<<5)-t+r,t=t&t}return Math.abs(t).toString(36)}generateSequenceNumber(){return`${Date.now()}${this.sequenceCounter++}`.padStart(20,"0")}updateMessageGroup(e,t){let a=`${e}-${t}`,r=this.messageGroups.get(a);if(!r)r={id:`group-${Date.now()}-${this.groupCounter++}`,messageGroupId:t,queueId:e,messagesInFlight:0},this.messageGroups.set(a,r);r.messagesInFlight++,r.lastMessageTimestamp=new Date}getMessageGroups(e){return Array.from(this.messageGroups.values()).filter((t)=>t.queueId===e)}getQueue(e){return this.queues.get(e)}listQueues(){return Array.from(this.queues.values())}getMessages(e,t){let a=Array.from(this.messages.values());if(t)a=a.filter((r)=>r.messageGroupId===t);return a.sort((r,n)=>r.sequenceNumber.localeCompare(n.sequenceNumber))}generateFIFOQueueCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:e.name,FifoQueue:!0,ContentBasedDeduplication:e.contentBasedDeduplication,DeduplicationScope:e.deduplicationScope,FifoThroughputLimit:e.fifoThroughputLimit,MessageRetentionPeriod:e.messageRetentionPeriod,VisibilityTimeout:e.visibilityTimeout,ReceiveMessageWaitTimeSeconds:e.receiveMessageWaitTime,...e.deadLetterTargetArn&&{RedrivePolicy:{deadLetterTargetArn:e.deadLetterTargetArn,maxReceiveCount:e.maxReceiveCount||3}}}}}clear(){this.queues.clear(),this.messageGroups.clear(),this.deduplicationConfigs.clear(),this.messages.clear(),this.queueCounter=0,this.groupCounter=0,this.deduplicationCounter=0,this.messageCounter=0,this.sequenceCounter=0}}var xm=new sn;class on{monitors=new Map;metrics=new Map;alerts=new Map;reprocessJobs=new Map;monitorCounter=0;metricsCounter=0;alertCounter=0;jobCounter=0;createDLQMonitor(e){let t=`dlq-monitor-${Date.now()}-${this.monitorCounter++}`,a={id:t,...e};return this.monitors.set(t,a),a}createAutomatedMonitor(e){return this.createDLQMonitor({name:e.name,queueUrl:e.queueUrl,sourceQueues:e.sourceQueues,maxReceiveCount:3,alarmThreshold:10,autoReprocess:!0,reprocessStrategy:"scheduled",notificationTopicArn:e.notificationTopicArn})}collectMetrics(e){let t={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:e,timestamp:new Date,approximateNumberOfMessages:Math.floor(Math.random()*100),approximateAgeOfOldestMessage:Math.floor(Math.random()*86400),messagesReceived:Math.floor(Math.random()*50),messagesDeleted:Math.floor(Math.random()*30),messagesReprocessed:Math.floor(Math.random()*20)},a=this.metrics.get(e)||[];return a.push(t),this.metrics.set(e,a),this.checkForAlerts(e,t),t}checkForAlerts(e,t){let a=Array.from(this.monitors.values()).find((n)=>n.queueUrl===e);if(!a)return;if(t.approximateNumberOfMessages>=a.alarmThreshold)this.createAlert({monitorId:a.id,alertType:"threshold_exceeded",severity:"high",message:`DLQ ${a.name} has ${t.approximateNumberOfMessages} messages (threshold: ${a.alarmThreshold})`});let r=3600;if(t.approximateAgeOfOldestMessage>r)this.createAlert({monitorId:a.id,alertType:"old_message",severity:"medium",message:`DLQ ${a.name} has messages older than ${r} seconds`})}createAlert(e){let t=`alert-${Date.now()}-${this.alertCounter++}`,a={id:t,timestamp:new Date,acknowledged:!1,...e};return this.alerts.set(t,a),a}acknowledgeAlert(e){let t=this.alerts.get(e);if(!t)throw Error(`Alert not found: ${e}`);return t.acknowledged=!0,t}createReprocessJob(e){let t=`reprocess-${Date.now()}-${this.jobCounter++}`,a={id:t,queueUrl:e.queueUrl,messageId:e.messageId,attempts:0,status:"pending"};return this.reprocessJobs.set(t,a),a}async executeReprocessJob(e){let t=this.reprocessJobs.get(e);if(!t)throw Error(`Reprocess job not found: ${e}`);t.status="processing",t.startedAt=new Date,t.attempts++,await new Promise((r)=>setTimeout(r,100));let a=Math.random()>0.3;if(t.status=a?"success":"failed",t.completedAt=new Date,!a)t.error="Reprocessing failed - original error still present";return t}async batchReprocess(e){let t=[];for(let a=0;a<e.maxMessages;a++){let r=this.createReprocessJob({queueUrl:e.queueUrl,messageId:`msg-${a}`});await this.executeReprocessJob(r.id),t.push(r)}return t}getDLQStatistics(e,t=24){let a=new Date(Date.now()-t*60*60*1000),r=(this.metrics.get(e)||[]).filter((u)=>u.timestamp>=a);if(r.length===0)return{totalMessages:0,avgAge:0,messagesReceived:0,messagesDeleted:0,messagesReprocessed:0,successRate:0};let n=r[r.length-1],i=r.reduce((u,m)=>u+m.messagesReceived,0),s=r.reduce((u,m)=>u+m.messagesDeleted,0),o=r.reduce((u,m)=>u+m.messagesReprocessed,0),c=r.reduce((u,m)=>u+m.approximateAgeOfOldestMessage,0)/r.length,l=o>0?s/o*100:0;return{totalMessages:n.approximateNumberOfMessages,avgAge:c,messagesReceived:i,messagesDeleted:s,messagesReprocessed:o,successRate:l}}getMonitor(e){return this.monitors.get(e)}listMonitors(){return Array.from(this.monitors.values())}getAlerts(e,t){let a=Array.from(this.alerts.values());if(e)a=a.filter((r)=>r.monitorId===e);if(t!==void 0)a=a.filter((r)=>r.acknowledged===t);return a.sort((r,n)=>n.timestamp.getTime()-r.timestamp.getTime())}getReprocessJobs(e){let t=Array.from(this.reprocessJobs.values());if(e)t=t.filter((a)=>a.queueUrl===e);return t}generateDLQAlarmCF(e){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e.name}-messages-alarm`,AlarmDescription:`Alert when DLQ ${e.name} exceeds threshold`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:1,Threshold:e.alarmThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:e.queueUrl.split("/").pop()}],...e.notificationTopicArn&&{AlarmActions:[e.notificationTopicArn]}}}}clear(){this.monitors.clear(),this.metrics.clear(),this.alerts.clear(),this.reprocessJobs.clear(),this.monitorCounter=0,this.metricsCounter=0,this.alertCounter=0,this.jobCounter=0}}var Om=new on;class cn{configs=new Map;jobs=new Map;metrics=new Map;configCounter=0;jobCounter=0;metricsCounter=0;createBatchConfig(e){let t=`batch-config-${Date.now()}-${this.configCounter++}`,a={id:t,...e};return this.configs.set(t,a),a}createHighThroughputConfig(e){return this.createBatchConfig({queueUrl:e.queueUrl,batchSize:10,maxWaitTime:100,parallelProcessors:10,retryAttempts:3,visibilityTimeout:30})}createLowLatencyConfig(e){return this.createBatchConfig({queueUrl:e.queueUrl,batchSize:1,maxWaitTime:0,parallelProcessors:5,retryAttempts:2,visibilityTimeout:10})}createBatchJob(e){let t=`batch-job-${Date.now()}-${this.jobCounter++}`;if(!this.configs.get(e.configId))throw Error(`Batch config not found: ${e.configId}`);let a=[];for(let n=0;n<e.messageCount;n++)a.push({id:`msg-${t}-${n}`,messageId:`${t}-${n}`,body:`Message ${n}`,receiptHandle:`receipt-${t}-${n}`,attributes:{},status:"pending"});let r={id:t,configId:e.configId,messages:a,status:"pending",processedCount:0,failedCount:0};return this.jobs.set(t,r),r}async processBatchJob(e){let t=this.jobs.get(e);if(!t)throw Error(`Batch job not found: ${e}`);let a=this.configs.get(t.configId);if(!a)throw Error(`Batch config not found: ${t.configId}`);t.status="processing",t.startedAt=new Date;let r=this.chunkArray(t.messages,a.batchSize);for(let n of r)await this.processBatch(n,a);return t.processedCount=t.messages.filter((n)=>n.status==="success").length,t.failedCount=t.messages.filter((n)=>n.status==="failed").length,t.status=t.failedCount===0?"completed":"failed",t.completedAt=new Date,this.collectProcessorMetrics(a.id,t),t}async processBatch(e,t){let a=e.map((r)=>this.processMessage(r,t));await Promise.all(a)}async processMessage(e,t){e.status="processing";let a=Date.now();await new Promise((n)=>setTimeout(n,Math.random()*100));let r=Date.now()-a;if(e.processingTime=r,Math.random()>0.1)e.status="success";else e.status="failed",e.error="Processing error"}chunkArray(e,t){let a=[];for(let r=0;r<e.length;r+=t)a.push(e.slice(r,r+t));return a}collectProcessorMetrics(e,t){let a=`metrics-${Date.now()}-${this.metricsCounter++}`,r=t.messages.filter((u)=>u.status==="success").map((u)=>u.processingTime||0).filter((u)=>u>0),n=r.length>0?r.reduce((u,m)=>u+m,0)/r.length:0,i=t.completedAt&&t.startedAt?(t.completedAt.getTime()-t.startedAt.getTime())/1000:1,s=t.processedCount/i,o=t.messages.length>0?t.failedCount/t.messages.length*100:0,c={id:a,configId:e,timestamp:new Date,messagesProcessed:t.processedCount,averageProcessingTime:n,throughput:s,errorRate:o},l=this.metrics.get(e)||[];l.push(c),this.metrics.set(e,l)}getBatchStatistics(e){let t=this.metrics.get(e)||[];if(t.length===0)return{totalJobsProcessed:0,totalMessagesProcessed:0,averageThroughput:0,averageErrorRate:0,averageProcessingTime:0};let a=t.reduce((s,o)=>s+o.messagesProcessed,0),r=t.reduce((s,o)=>s+o.throughput,0)/t.length,n=t.reduce((s,o)=>s+o.errorRate,0)/t.length,i=t.reduce((s,o)=>s+o.averageProcessingTime,0)/t.length;return{totalJobsProcessed:t.length,totalMessagesProcessed:a,averageThroughput:r,averageErrorRate:n,averageProcessingTime:i}}optimizeBatchConfig(e){let t=this.configs.get(e);if(!t)throw Error(`Batch config not found: ${e}`);let a=this.getBatchStatistics(e);if(a.averageErrorRate<5&&t.batchSize<10)t.batchSize=Math.min(10,t.batchSize+1);if(a.averageErrorRate>20&&t.batchSize>1)t.batchSize=Math.max(1,t.batchSize-1);if(a.averageThroughput<5&&t.parallelProcessors<20)t.parallelProcessors++;return t}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getJob(e){return this.jobs.get(e)}listJobs(e){let t=Array.from(this.jobs.values());if(e)t=t.filter((a)=>a.configId===e);return t}generateBatchProcessorCF(e){return{Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:`arn:aws:sqs:us-east-1:123456789012:${e.queueUrl.split("/").pop()}`,FunctionName:"batch-processor-function",BatchSize:e.batchSize,MaximumBatchingWindowInSeconds:e.maxWaitTime/1000,FunctionResponseTypes:["ReportBatchItemFailures"]}}}clear(){this.configs.clear(),this.jobs.clear(),this.metrics.clear(),this.configCounter=0,this.jobCounter=0,this.metricsCounter=0}}var Bm=new cn;class ln{queues=new Map;retentionPolicies=new Map;delayQueues=new Map;purgeOperations=new Map;metrics=new Map;queueCounter=0;retentionCounter=0;delayCounter=0;purgeCounter=0;metricsCounter=0;createQueue(e){let t=`queue-${Date.now()}-${this.queueCounter++}`,a={id:t,purgeInProgress:!1,...e};return this.queues.set(t,a),a}createStandardQueue(e){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${e.queueName}`,queueName:e.queueName,messageRetentionPeriod:(e.messageRetentionDays||4)*24*60*60,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:0})}createLongPollingQueue(e){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${e.queueName}`,queueName:e.queueName,messageRetentionPeriod:345600,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:e.waitTimeSeconds||20})}createRetentionPolicy(e){let t=`retention-${Date.now()}-${this.retentionCounter++}`,a={id:t,...e};this.retentionPolicies.set(t,a);let r=this.queues.get(e.queueId);if(r)r.messageRetentionPeriod=e.retentionPeriod;return a}createShortRetentionPolicy(e){return this.createRetentionPolicy({queueId:e.queueId,retentionPeriod:e.retentionHours*60*60,autoCleanup:!0,archiveExpiredMessages:!1})}createArchivalRetentionPolicy(e){return this.createRetentionPolicy({queueId:e.queueId,retentionPeriod:e.retentionDays*24*60*60,autoCleanup:!0,cleanupSchedule:"cron(0 0 * * ? *)",archiveExpiredMessages:!0,archiveS3Bucket:e.s3Bucket})}createDelayQueue(e){let t=`delay-${Date.now()}-${this.delayCounter++}`,a={id:t,...e};this.delayQueues.set(t,a);let r=Array.from(this.queues.values()).find((n)=>n.queueUrl===e.queueUrl);if(r)r.delaySeconds=e.defaultDelay;return a}createScheduledDelayQueue(e){return this.createDelayQueue({queueUrl:e.queueUrl,defaultDelay:e.delayMinutes*60,perMessageDelay:!1,maxDelay:900})}async purgeQueue(e){let t=this.queues.get(e);if(!t)throw Error(`Queue not found: ${e}`);if(t.purgeInProgress)throw Error("Purge already in progress for this queue");let a=`purge-${Date.now()}-${this.purgeCounter++}`,r={id:a,queueUrl:t.queueUrl,status:"in_progress",startedAt:new Date};return this.purgeOperations.set(a,r),t.purgeInProgress=!0,setTimeout(()=>{r.status="completed",r.completedAt=new Date,r.messagesPurged=Math.floor(Math.random()*1000),t.purgeInProgress=!1},100),r}collectQueueMetrics(e){let t={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:e,timestamp:new Date,approximateNumberOfMessages:Math.floor(Math.random()*1000),approximateNumberOfMessagesNotVisible:Math.floor(Math.random()*100),approximateNumberOfMessagesDelayed:Math.floor(Math.random()*50),oldestMessageAge:Math.floor(Math.random()*86400)},a=this.metrics.get(e)||[];return a.push(t),this.metrics.set(e,a),t}getQueueHealth(e){let t=this.metrics.get(e)||[];if(t.length===0)return{status:"healthy",issues:[],recommendations:[]};let a=t[t.length-1],r=[],n=[],i="healthy";if(a.approximateNumberOfMessages>1e4)i="critical",r.push("Large message backlog detected"),n.push("Increase consumer capacity");else if(a.approximateNumberOfMessages>1000)i="warning",r.push("Growing message backlog"),n.push("Monitor consumer performance");if(a.oldestMessageAge&&a.oldestMessageAge>3600){if(i!=="critical")i="warning";r.push("Old messages in queue"),n.push("Review message processing")}if(a.approximateNumberOfMessagesDelayed>100){if(i!=="critical")i="warning";r.push("High number of delayed messages")}return{status:i,issues:r,recommendations:n}}getQueue(e){return this.queues.get(e)}listQueues(){return Array.from(this.queues.values())}getRetentionPolicy(e){return this.retentionPolicies.get(e)}listRetentionPolicies(){return Array.from(this.retentionPolicies.values())}getPurgeOperations(e){let t=Array.from(this.purgeOperations.values());if(e)t=t.filter((a)=>a.queueUrl===e);return t}generateQueueCF(e){return{Type:"AWS::SQS::Queue",Properties:{QueueName:e.queueName,MessageRetentionPeriod:e.messageRetentionPeriod,DelaySeconds:e.delaySeconds,MaximumMessageSize:e.maximumMessageSize,ReceiveMessageWaitTimeSeconds:e.receiveMessageWaitTime}}}generateCleanupRuleCF(e){return{Type:"AWS::Events::Rule",Properties:{Name:`${e.id}-cleanup`,Description:"Automated queue cleanup",ScheduleExpression:e.cleanupSchedule||"cron(0 0 * * ? *)",State:"ENABLED",Targets:[{Arn:"arn:aws:lambda:us-east-1:123456789012:function:queue-cleanup",Id:e.id,Input:JSON.stringify({queueId:e.queueId,archiveBucket:e.archiveS3Bucket})}]}}}clear(){this.queues.clear(),this.retentionPolicies.clear(),this.delayQueues.clear(),this.purgeOperations.clear(),this.metrics.clear(),this.queueCounter=0,this.retentionCounter=0,this.delayCounter=0,this.purgeCounter=0,this.metricsCounter=0}}var _m=new ln,Io=(()=>{let e=[];for(let t=0;t<256;t++){let a=t;for(let r=0;r<8;r++)a=a&1?3988292384^a>>>1:a>>>1;e[t]=a>>>0}return e})();function Ro(e){let t=4294967295;for(let a=0;a<e.length;a++)t=Io[(t^e[a])&255]^t>>>8;return(t^4294967295)>>>0}function No(e){if(typeof e==="string")return Buffer.from(e,"utf-8");if(Buffer.isBuffer(e))return e;return Buffer.from(e)}function Do(e){let t=Math.max(1980,e.getFullYear()),a=(e.getHours()<<11|e.getMinutes()<<5|e.getSeconds()>>1)&65535,r=(t-1980<<9|e.getMonth()+1<<5|e.getDate())&65535;return{time:a,date:r}}function rt(e){let t=[],a=[],r=0;for(let s of e){let o=No(s.data),c=Po(o),l=Ro(o),u=Buffer.from(s.name.replace(/\\/g,"/"),"utf-8"),{time:m,date:p}=Do(s.date??new Date(0)),g=s.mode??420,h=Buffer.alloc(30+u.length);h.writeUInt32LE(67324752,0),h.writeUInt16LE(20,4),h.writeUInt16LE(0,6),h.writeUInt16LE(8,8),h.writeUInt16LE(m,10),h.writeUInt16LE(p,12),h.writeUInt32LE(l,14),h.writeUInt32LE(c.length,18),h.writeUInt32LE(o.length,22),h.writeUInt16LE(u.length,26),h.writeUInt16LE(0,28),u.copy(h,30);let y=Buffer.alloc(46+u.length);y.writeUInt32LE(33639248,0),y.writeUInt16LE(798,4),y.writeUInt16LE(20,6),y.writeUInt16LE(0,8),y.writeUInt16LE(8,10),y.writeUInt16LE(m,12),y.writeUInt16LE(p,14),y.writeUInt32LE(l,16),y.writeUInt32LE(c.length,20),y.writeUInt32LE(o.length,24),y.writeUInt16LE(u.length,28),y.writeUInt16LE(0,30),y.writeUInt16LE(0,32),y.writeUInt16LE(0,34),y.writeUInt16LE(0,36),y.writeUInt32LE((g&65535)<<16,38),y.writeUInt32LE(r,42),u.copy(y,46),t.push(h,c),a.push(y),r+=h.length+c.length}let n=Buffer.concat(a),i=Buffer.alloc(22);return i.writeUInt32LE(101010256,0),i.writeUInt16LE(0,4),i.writeUInt16LE(0,6),i.writeUInt16LE(e.length,8),i.writeUInt16LE(e.length,10),i.writeUInt32LE(n.length,12),i.writeUInt32LE(r,16),i.writeUInt16LE(0,20),Buffer.concat([...t,n,i])}function ko(e){let t=e.adapterImport??"./adapter",a=e.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
|
|
7265
7265
|
import * as __userModule from ${JSON.stringify(a)}
|
|
7266
7266
|
import { resolveApp, createHandlers } from ${JSON.stringify(t)}
|
|
7267
7267
|
|
|
@@ -7271,9 +7271,9 @@ const __handlers = createHandlers(__app)
|
|
|
7271
7271
|
export const http = __handlers.http
|
|
7272
7272
|
export const queue = __handlers.queue
|
|
7273
7273
|
export const cli = __handlers.cli
|
|
7274
|
-
`}var
|
|
7274
|
+
`}var Uo=["adapter.ts","recursion.ts","auto-recursion.ts"];function jo(){return Le(Wo(Vo(import.meta.url)),"runtime")}function Ko(e,t,a){for(let r of e??[])a?.(`build: ${r}`),$o(r,{stdio:"inherit",cwd:t})}function Ho(e){return Lo("sha256").update(e).digest("hex")}function Hm(e,t,a){return`deployments/${e}/${t}/${a}.zip`}async function qm(e){let t=Fo(e.projectRoot??process.cwd()),{app:a}=e;if(!e.skipBuild)Ko(a.build,t,e.onStep);let r=a.entry;if(!r)throw Error("serverless app: `entry` is required to package a Node/Bun application");let n=Go(r)?r:Le(t,r),i=xo(Le(_o(),"tscloud-pkg-"));try{for(let p of Uo)Mo(Le(jo(),p),Le(i,p));let s=Le(i,"bootstrap.ts");Bo(s,ko({entryImport:n,adapterImport:"./adapter"})),e.onStep?.("bundling application");let o=await Bun.build({entrypoints:[s],target:a.kind==="bun"?"bun":"node",format:"esm",minify:!1,sourcemap:"none"});if(!o.success){let p=o.logs.map((g)=>String(g)).join(`
|
|
7275
7275
|
`);throw Error(`serverless app bundle failed:
|
|
7276
|
-
${p}`)}let c=o.outputs[0],l=Buffer.from(await c.arrayBuffer()),u="index",m=at([{name:`${u}.mjs`,data:l}]);return{zip:m,bundle:l,sha256:Ho(m),handlerFile:u,handlers:{http:a.handlers?.http??`${u}.http`,queue:a.handlers?.queue??`${u}.queue`,cli:a.handlers?.cli??`${u}.cli`},bundleBytes:l.length}}finally{Oo(i,{recursive:!0,force:!0})}}var qo=["18","20","22"];function zo(e){if(!e)return"22";let t=String(e).match(/(\d+)/);return t?t[1]:"22"}function Jo(e){let t=e.kind??"node";if(t==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(t==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let a=zo(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&qo.includes(a))return{lambdaRuntime:e.runtime&&e.runtime.startsWith("nodejs")?e.runtime:`nodejs${a}.x`,kind:"node",version:a,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:a,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function ln(e,t,a){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${t}-${a}-default`}];return e.queues.map((r)=>{if(typeof r==="string")return{name:`${t}-${a}-${r}`};let[n,i]=Object.entries(r)[0];return{name:`${t}-${a}-${n}`,concurrency:i}})}function zm(e,t,a){return ln(e,t,a).map((r)=>r.name)}function Jm(e){let{app:t,environment:a,handlers:r}=e,n=e.config.project.slug,i=Jo(t).lambdaRuntime,s=t.architecture??"x86_64",o=e.config.project.region,c={http:`${n}-${a}-http`,queue:`${n}-${a}-queue`,cli:`${n}-${a}-cli`};if(t.gatewayVersion===1)throw Error("serverless app: `gatewayVersion: 1` (REST API) is not supported — ts-cloud uses API Gateway HTTP API (v2). Remove `gatewayVersion` or set it to 2.");let l=ln(t,n,a),u=l.map((R)=>R.name),m=u.length>0,p=t.logRetention??14,g=t.packaging==="image";if(g&&t.lambdaInsights)throw Error("serverless app: `lambdaInsights` layer attachment is only supported for zip packaging. Container images must install the Lambda Insights extension in the image.");let h=(t.scheduler??"on")!=="off",y=(t.cache?.driver??"dynamodb")==="dynamodb",b=Boolean(t.assets),T=ni(n,a),w=t.tmpStorage??512,S={},E={},v=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:d.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:d.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${n}-${a}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[d.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${n}/${a}/*`),d.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${n}/${a}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[d.sub(`arn:aws:s3:::${T}`),d.sub(`arn:aws:s3:::${T}/*`),...t.storage?.bucket?[d.sub(`arn:aws:s3:::${t.storage.bucket}`),d.sub(`arn:aws:s3:::${t.storage.bucket}/*`)]:[]]}]}}];if(m)v[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:d.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${n}-${a}-*`)});if(y)v[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:d.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${n}-${a}-cache*`)});let P=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(t.vpc?.subnets?.length)P.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(t.lambdaInsights)P.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");S.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${n}-${a}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:P,Policies:v}};let N=(R)=>({TSCLOUD_LAMBDA_MODE:R,TSCLOUD_ENV:a,...t.octane?{TSCLOUD_OCTANE:"1"}:{},...t.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...y?{TSCLOUD_CACHE_TABLE:`${n}-${a}-cache`}:{},...m?{TSCLOUD_QUEUE:u[0]}:{},...t.env??{}}),I=Boolean(t.efs),D=typeof t.efs==="object"?t.efs:{},M=D.mountPath??"/mnt/local",O=I&&!D.accessPointArn,oe=D.accessPointArn??(O?d.getAtt("EfsAccessPoint","Arn"):void 0),j=t.vpc?.subnets??[],te=j.length>0,G=t.cache?.driver==="elasticache"||t.database?.connection==="aurora-serverless"||Boolean(t.rdsProxy)||I;if(G&&!te)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let ve=te?{VpcConfig:{SubnetIds:j,SecurityGroupIds:[...t.vpc?.securityGroups??[],...G?[d.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},Ue=O?j.map((R,x)=>`EfsMountTarget${x}`):[],Rt=I?{FileSystemConfigs:[{Arn:oe,LocalMountPath:M}]}:{};if(I)v[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function ce(R,x,L,V,de,rt,Se,nt=w){S[`${R}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${x}`,RetentionInDays:p}};let Nt=[...e.runtimeLayers??[],...t.lambdaInsights?[t.lambdaInsights.layerArn]:[]],Dt=g?{PackageType:"Image",Code:{ImageUri:d.ref("ImageUri")},...t.kind==="php"?{}:{ImageConfig:{Command:[L]}}}:{Runtime:i,Handler:L,Code:{S3Bucket:d.ref("ArtifactBucket"),S3Key:d.ref("ArtifactKey")},...Nt.length?{Layers:[...new Set(Nt)]}:{}};S[R]={Type:"AWS::Lambda::Function",DependsOn:[`${R}LogGroup`,...Ue],Properties:{FunctionName:x,Architectures:[s],MemorySize:de,Timeout:rt,Role:d.getAtt("AppRole","Arn"),Environment:{Variables:N(V)},EphemeralStorage:{Size:nt},...Dt,...Se!==void 0?{ReservedConcurrentExecutions:Se}:{},...ve,...Rt}}}if(ce("HttpFunction",c.http,r.http,"http",t.memory??1024,t.timeout??28,t.concurrency,w),ce("CliFunction",c.cli,r.cli,"cli",t.cliMemory??1024,t.cliTimeout??900,void 0,t.cliTmpStorage??w),m)ce("QueueFunction",c.queue,r.queue,"queue",t.queueMemory??1024,t.queueTimeout??120,void 0,t.queueTmpStorage??w);let ae=(t.provisionedConcurrency??0)>0?t.provisionedConcurrency:0,le=["HttpFunction","CliFunction",...m?["QueueFunction"]:[]];if(ae)for(let R of le)S[`${R}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:d.ref(R)}},S[`${R}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:d.ref(R),Name:"live",FunctionVersion:d.getAtt(`${R}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:ae}}};let we=(R)=>ae?d.ref(`${R}Alias`):d.getAtt(R,"Arn"),ue=(R)=>ae?d.ref(`${R}Alias`):d.ref(R);S.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${n}-${a}`,ProtocolType:"HTTP"}},S.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:d.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:we("HttpFunction"),PayloadFormatVersion:"2.0"}},S.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:d.ref("HttpApi"),RouteKey:"$default",Target:d.join("/",["integrations",d.ref("HttpIntegration")])}},S.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:d.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},S.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ue("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:d.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},E.HttpApiEndpoint={Description:"HTTP API endpoint",Value:d.getAtt("HttpApi","ApiEndpoint")},E.HttpApiId={Description:"HTTP API id",Value:d.ref("HttpApi")};let fe=(Array.isArray(t.domain)?t.domain:t.domain?[t.domain]:[]).filter(Boolean);if(fe.length){if(!t.certificateArn&&!t.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let R=t.certificateArn;if(!R)S.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:fe[0],...fe.length>1?{SubjectAlternativeNames:fe.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:fe.map((x)=>({DomainName:x,HostedZoneId:t.hostedZoneId}))}},R=d.ref("HttpCertificate");fe.forEach((x,L)=>{let V=`HttpDomain${L}`;if(S[V]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:x,DomainNameConfigurations:[{CertificateArn:R,EndpointType:"REGIONAL"}]}},S[`HttpApiMapping${L}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:d.ref("HttpApi"),DomainName:d.ref(V),Stage:"$default"}},t.hostedZoneId)S[`HttpDomainRecord${L}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t.hostedZoneId,Name:x,Type:"A",AliasTarget:{DNSName:d.getAtt(V,"RegionalDomainName"),HostedZoneId:d.getAtt(V,"RegionalHostedZoneId")}}};E[`CustomDomain${L}`]={Description:`Custom domain ${x}`,Value:x},E[`CustomDomainTarget${L}`]={Description:`Point ${x} (CNAME/alias) at this APIGW regional domain`,Value:d.getAtt(V,"RegionalDomainName")}})}if(m)S.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${n}-${a}-dlq`,MessageRetentionPeriod:1209600}},l.forEach((R,x)=>{let L=`AppQueue${x}`,V=t.queueTimeout??120;S[L]={Type:"AWS::SQS::Queue",Properties:{QueueName:R.name,VisibilityTimeout:Math.min(43200,V*6),RedrivePolicy:{deadLetterTargetArn:d.getAtt("AppQueueDlq","Arn"),maxReceiveCount:t.queueTries??3}}};let de=R.concurrency??t.queueConcurrency;S[`${L}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:d.getAtt(L,"Arn"),FunctionName:ue("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...de?{ScalingConfig:{MaximumConcurrency:Math.max(2,de)}}:{}}},E[`QueueUrl${x}`]={Description:`Queue URL: ${R.name}`,Value:d.ref(L)}});if(h)S.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${n}-${a}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:we("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},S.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ue("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:d.getAtt("SchedulerRule","Arn")}};if(t.warm&&t.warm>0){let R={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},x=(t.warmFunctions??["http"]).filter((L)=>L!=="queue"||m);for(let L of x){let V=L.charAt(0).toUpperCase()+L.slice(1),de=Math.ceil(t.warm/5),rt=0;for(let Se=0;Se<de;Se++){let nt=Math.min(5,t.warm-rt);S[`Warmer${V}Rule${Se}`]={Type:"AWS::Events::Rule",Properties:{Name:`${n}-${a}-warmer-${L}-${Se}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:nt},(Nt,Dt)=>({Id:`warm-${L}-${Se}-${Dt}`,Arn:d.getAtt(R[L],"Arn"),Input:JSON.stringify({warmer:!0})}))}},rt+=nt}S[`Warmer${V}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:d.ref(R[L]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:d.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${n}-${a}-warmer-${L}-*`)}}}}if(y)S.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n}-${a}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},E.CacheTableName={Description:"DynamoDB cache table",Value:d.ref("CacheTable")};if(b){if(S.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:T,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},S.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${n}-${a}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},S.AssetsDistribution={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,DefaultCacheBehavior:{TargetOriginId:"assets",ViewerProtocolPolicy:"redirect-to-https",Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},Origins:[{Id:"assets",DomainName:d.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:d.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...t.assetDomain?{Aliases:[t.assetDomain],ViewerCertificate:{AcmCertificateArn:t.assetCertificateArn??d.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},t.assetDomain){if(!t.assetCertificateArn){if(!t.hostedZoneId)throw Error("serverless app: `assetDomain` requires either `assetCertificateArn` (a us-east-1 ACM cert) or `hostedZoneId` (to auto-issue + validate one). CloudFront only accepts certs from us-east-1.");if(o!=="us-east-1")throw Error(`serverless app: auto-issuing an asset-domain cert needs a us-east-1 app (CloudFront certs must be us-east-1); this app is in ${o}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);S.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:t.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:t.assetDomain,HostedZoneId:t.hostedZoneId}]}}}if(t.hostedZoneId)S.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t.hostedZoneId,Name:t.assetDomain,Type:"A",AliasTarget:{DNSName:d.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};E.AssetDomain={Description:"Custom asset CDN host",Value:t.assetDomain}}S.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:d.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:d.sub(`arn:aws:s3:::${T}/*`),Condition:{StringEquals:{"AWS:SourceArn":d.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},E.AssetsBucketName={Description:"Assets bucket",Value:d.ref("AssetsBucket")},E.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:d.getAtt("AssetsDistribution","DomainName")}}if(t.firewall?.enabled){let R=[],x=0;if(t.firewall.rateLimit)R.push({Name:"rate-limit",Priority:x++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:t.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n}-${a}-rate`}});let L={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let V of t.firewall.rules??[]){let de=L[V];if(!de)continue;R.push({Name:`managed-${V}`,Priority:x++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:de}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n}-${a}-${V}`}})}S.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${n}-${a}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:R,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n}-${a}-waf`}}},E.WafAclArn={Description:"WAF web ACL ARN. Attach to a CloudFront distribution fronting the API to enforce (HTTP API v2 stages do not support direct WAF association).",Value:d.getAtt("WebAcl","Arn")}}if(te&&G){if(!t.vpc?.id)throw Error("serverless app: data services (elasticache / aurora-serverless / rdsProxy / efs) need app.vpc.id (the VPC id) so the managed security group is created in the right VPC.");S.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:t.vpc.id,GroupDescription:`${n}-${a} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(O)S.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${n}-${a}-efs`}]}},j.forEach((R,x)=>{S[`EfsMountTarget${x}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:d.ref("EfsFileSystem"),SubnetId:R,SecurityGroups:[d.getAtt("DataSecurityGroup","GroupId")]}}}),S.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:d.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},E.EfsFileSystemId={Description:"EFS file system id",Value:d.ref("EfsFileSystem")};if(t.cache?.driver==="elasticache")S.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${n}-${a} cache subnets`,SubnetIds:j}},S.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${n}-${a}-cache`,ReplicationGroupDescription:`${n}-${a} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),SecurityGroupIds:[d.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},E.CacheEndpoint={Description:"Redis primary endpoint",Value:d.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(t.database?.connection==="aurora-serverless")S.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${n}-${a} db subnets`,SubnetIds:j}},S.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${n}/${a}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},S.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${n}-${a}-db`,DatabaseName:"app",MasterUsername:d.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:d.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:t.database?.minCapacity??0.5,MaxCapacity:t.database?.maxCapacity??4},DBSubnetGroupName:d.ref("DbSubnetGroup"),VpcSecurityGroupIds:[d.getAtt("DataSecurityGroup","GroupId")]}},S.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:d.ref("DbCluster")}},E.DbEndpoint={Description:"Aurora cluster endpoint",Value:d.getAtt("DbCluster","Endpoint.Address")};if(t.rdsProxy&&t.database?.connection==="aurora-serverless")S.DbProxyRole={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"read-db-secret",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:d.ref("DbSecret")}]}}]}},S.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof t.rdsProxy==="object"&&t.rdsProxy.name?t.rdsProxy.name:`${n}-${a}-proxy`,EngineFamily:"MYSQL",RoleArn:d.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:d.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:j,VpcSecurityGroupIds:[d.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},S.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:d.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[d.ref("DbCluster")]}},E.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:d.getAtt("DbProxy","Endpoint")};if(E.HttpFunctionName={Description:"HTTP function name",Value:d.ref("HttpFunction")},E.CliFunctionName={Description:"CLI function name",Value:d.ref("CliFunction")},m)E.QueueFunctionName={Description:"Queue function name",Value:d.ref("QueueFunction")};let ke={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${n}-${a})`,Parameters:g?{ImageUri:{Type:"String",Description:"ECR image URI of the deployment artifact"}}:{ArtifactBucket:{Type:"String",Description:"S3 bucket holding the deployment artifact"},ArtifactKey:{Type:"String",Description:"S3 key of the deployment artifact (zip)"}},Resources:S,Outputs:E},Ge={};for(let R of Object.values(S))Ge[R.Type]=(Ge[R.Type]??0)+1;return{template:ke,functionNames:c,queueNames:u,resourceSummary:Ge}}var Qo=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function $o(e){let t=`php${e.replace(".","")}`;return Qo.map((a)=>`${t}-php-${a}`)}function un(e,t){let a=`php${e.replace(".","")}`,r=$o(e).join(" \\\n "),n=`/opt/remi/${a}/root`,i=`/etc/opt/remi/${a}`;return`${t?`FROM almalinux:9 AS ${t}`:"FROM almalinux:9"}
|
|
7276
|
+
${p}`)}let c=o.outputs[0],l=Buffer.from(await c.arrayBuffer()),u="index",m=rt([{name:`${u}.mjs`,data:l}]);return{zip:m,bundle:l,sha256:Ho(m),handlerFile:u,handlers:{http:a.handlers?.http??`${u}.http`,queue:a.handlers?.queue??`${u}.queue`,cli:a.handlers?.cli??`${u}.cli`},bundleBytes:l.length}}finally{Oo(i,{recursive:!0,force:!0})}}var qo=["18","20","22"];function zo(e){if(!e)return"22";let t=String(e).match(/(\d+)/);return t?t[1]:"22"}function Qo(e){let t=e.kind??"node";if(t==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(t==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let a=zo(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&qo.includes(a))return{lambdaRuntime:e.runtime&&e.runtime.startsWith("nodejs")?e.runtime:`nodejs${a}.x`,kind:"node",version:a,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:a,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function un(e,t,a){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${t}-${a}-default`}];return e.queues.map((r)=>{if(typeof r==="string")return{name:`${t}-${a}-${r}`};let[n,i]=Object.entries(r)[0];return{name:`${t}-${a}-${n}`,concurrency:i}})}function zm(e,t,a){return un(e,t,a).map((r)=>r.name)}function Qm(e){let{app:t,environment:a,handlers:r}=e,n=e.config.project.slug,i=Qo(t).lambdaRuntime,s=t.architecture??"x86_64",o=e.config.project.region,c={http:`${n}-${a}-http`,queue:`${n}-${a}-queue`,cli:`${n}-${a}-cli`};if(t.gatewayVersion===1)throw Error("serverless app: `gatewayVersion: 1` (REST API) is not supported — ts-cloud uses API Gateway HTTP API (v2). Remove `gatewayVersion` or set it to 2.");let l=un(t,n,a),u=l.map((R)=>R.name),m=u.length>0,p=t.logRetention??14,g=t.packaging==="image";if(g&&t.lambdaInsights)throw Error("serverless app: `lambdaInsights` layer attachment is only supported for zip packaging. Container images must install the Lambda Insights extension in the image.");let h=(t.scheduler??"on")!=="off",y=(t.cache?.driver??"dynamodb")==="dynamodb",b=Boolean(t.assets),T=ii(n,a),w=t.tmpStorage??512,S={},E={},v=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:d.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:d.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${n}-${a}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[d.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${n}/${a}/*`),d.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${n}/${a}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[d.sub(`arn:aws:s3:::${T}`),d.sub(`arn:aws:s3:::${T}/*`),...t.storage?.bucket?[d.sub(`arn:aws:s3:::${t.storage.bucket}`),d.sub(`arn:aws:s3:::${t.storage.bucket}/*`)]:[]]}]}}];if(m)v[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:d.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${n}-${a}-*`)});if(y)v[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:d.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${n}-${a}-cache*`)});let P=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(t.vpc?.subnets?.length)P.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(t.lambdaInsights)P.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");S.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${n}-${a}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:P,Policies:v}};let N=(R)=>({TSCLOUD_LAMBDA_MODE:R,TSCLOUD_ENV:a,...t.octane?{TSCLOUD_OCTANE:"1"}:{},...t.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...y?{TSCLOUD_CACHE_TABLE:`${n}-${a}-cache`}:{},...m?{TSCLOUD_QUEUE:u[0]}:{},...t.env??{}}),I=Boolean(t.efs),D=typeof t.efs==="object"?t.efs:{},L=D.mountPath??"/mnt/local",O=I&&!D.accessPointArn,ce=D.accessPointArn??(O?d.getAtt("EfsAccessPoint","Arn"):void 0),j=t.vpc?.subnets??[],ae=j.length>0,F=t.cache?.driver==="elasticache"||t.database?.connection==="aurora-serverless"||Boolean(t.rdsProxy)||I;if(F&&!ae)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let we=ae?{VpcConfig:{SubnetIds:j,SecurityGroupIds:[...t.vpc?.securityGroups??[],...F?[d.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},Ge=O?j.map((R,x)=>`EfsMountTarget${x}`):[],Nt=I?{FileSystemConfigs:[{Arn:ce,LocalMountPath:L}]}:{};if(I)v[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function le(R,x,M,V,me,nt,be,it=w){S[`${R}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${x}`,RetentionInDays:p}};let Dt=[...e.runtimeLayers??[],...t.lambdaInsights?[t.lambdaInsights.layerArn]:[]],kt=g?{PackageType:"Image",Code:{ImageUri:d.ref("ImageUri")},...t.kind==="php"?{}:{ImageConfig:{Command:[M]}}}:{Runtime:i,Handler:M,Code:{S3Bucket:d.ref("ArtifactBucket"),S3Key:d.ref("ArtifactKey")},...Dt.length?{Layers:[...new Set(Dt)]}:{}};S[R]={Type:"AWS::Lambda::Function",DependsOn:[`${R}LogGroup`,...Ge],Properties:{FunctionName:x,Architectures:[s],MemorySize:me,Timeout:nt,Role:d.getAtt("AppRole","Arn"),Environment:{Variables:N(V)},EphemeralStorage:{Size:it},...kt,...be!==void 0?{ReservedConcurrentExecutions:be}:{},...we,...Nt}}}if(le("HttpFunction",c.http,r.http,"http",t.memory??1024,t.timeout??28,t.concurrency,w),le("CliFunction",c.cli,r.cli,"cli",t.cliMemory??1024,t.cliTimeout??900,void 0,t.cliTmpStorage??w),m)le("QueueFunction",c.queue,r.queue,"queue",t.queueMemory??1024,t.queueTimeout??120,void 0,t.queueTmpStorage??w);let re=(t.provisionedConcurrency??0)>0?t.provisionedConcurrency:0,ue=["HttpFunction","CliFunction",...m?["QueueFunction"]:[]];if(re)for(let R of ue)S[`${R}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:d.ref(R)}},S[`${R}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:d.ref(R),Name:"live",FunctionVersion:d.getAtt(`${R}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:re}}};let Ee=(R)=>re?d.ref(`${R}Alias`):d.getAtt(R,"Arn"),de=(R)=>re?d.ref(`${R}Alias`):d.ref(R);S.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${n}-${a}`,ProtocolType:"HTTP"}},S.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:d.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:Ee("HttpFunction"),PayloadFormatVersion:"2.0"}},S.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:d.ref("HttpApi"),RouteKey:"$default",Target:d.join("/",["integrations",d.ref("HttpIntegration")])}},S.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:d.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},S.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:de("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:d.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},E.HttpApiEndpoint={Description:"HTTP API endpoint",Value:d.getAtt("HttpApi","ApiEndpoint")},E.HttpApiId={Description:"HTTP API id",Value:d.ref("HttpApi")};let Se=(Array.isArray(t.domain)?t.domain:t.domain?[t.domain]:[]).filter(Boolean);if(Se.length){if(!t.certificateArn&&!t.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let R=t.certificateArn;if(!R)S.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:Se[0],...Se.length>1?{SubjectAlternativeNames:Se.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:Se.map((x)=>({DomainName:x,HostedZoneId:t.hostedZoneId}))}},R=d.ref("HttpCertificate");Se.forEach((x,M)=>{let V=`HttpDomain${M}`;if(S[V]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:x,DomainNameConfigurations:[{CertificateArn:R,EndpointType:"REGIONAL"}]}},S[`HttpApiMapping${M}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:d.ref("HttpApi"),DomainName:d.ref(V),Stage:"$default"}},t.hostedZoneId)S[`HttpDomainRecord${M}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t.hostedZoneId,Name:x,Type:"A",AliasTarget:{DNSName:d.getAtt(V,"RegionalDomainName"),HostedZoneId:d.getAtt(V,"RegionalHostedZoneId")}}};E[`CustomDomain${M}`]={Description:`Custom domain ${x}`,Value:x},E[`CustomDomainTarget${M}`]={Description:`Point ${x} (CNAME/alias) at this APIGW regional domain`,Value:d.getAtt(V,"RegionalDomainName")}})}if(m)S.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${n}-${a}-dlq`,MessageRetentionPeriod:1209600}},l.forEach((R,x)=>{let M=`AppQueue${x}`,V=t.queueTimeout??120;S[M]={Type:"AWS::SQS::Queue",Properties:{QueueName:R.name,VisibilityTimeout:Math.min(43200,V*6),RedrivePolicy:{deadLetterTargetArn:d.getAtt("AppQueueDlq","Arn"),maxReceiveCount:t.queueTries??3}}};let me=R.concurrency??t.queueConcurrency;S[`${M}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:d.getAtt(M,"Arn"),FunctionName:de("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...me?{ScalingConfig:{MaximumConcurrency:Math.max(2,me)}}:{}}},E[`QueueUrl${x}`]={Description:`Queue URL: ${R.name}`,Value:d.ref(M)}});if(h)S.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${n}-${a}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:Ee("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},S.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:de("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:d.getAtt("SchedulerRule","Arn")}};if(t.warm&&t.warm>0){let R={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},x=(t.warmFunctions??["http"]).filter((M)=>M!=="queue"||m);for(let M of x){let V=M.charAt(0).toUpperCase()+M.slice(1),me=Math.ceil(t.warm/5),nt=0;for(let be=0;be<me;be++){let it=Math.min(5,t.warm-nt);S[`Warmer${V}Rule${be}`]={Type:"AWS::Events::Rule",Properties:{Name:`${n}-${a}-warmer-${M}-${be}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:it},(Dt,kt)=>({Id:`warm-${M}-${be}-${kt}`,Arn:d.getAtt(R[M],"Arn"),Input:JSON.stringify({warmer:!0})}))}},nt+=it}S[`Warmer${V}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:d.ref(R[M]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:d.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${n}-${a}-warmer-${M}-*`)}}}}if(y)S.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n}-${a}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},E.CacheTableName={Description:"DynamoDB cache table",Value:d.ref("CacheTable")};if(b){if(S.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:T,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},S.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${n}-${a}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},S.AssetsDistribution={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,DefaultCacheBehavior:{TargetOriginId:"assets",ViewerProtocolPolicy:"redirect-to-https",Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},Origins:[{Id:"assets",DomainName:d.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:d.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...t.assetDomain?{Aliases:[t.assetDomain],ViewerCertificate:{AcmCertificateArn:t.assetCertificateArn??d.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},t.assetDomain){if(!t.assetCertificateArn){if(!t.hostedZoneId)throw Error("serverless app: `assetDomain` requires either `assetCertificateArn` (a us-east-1 ACM cert) or `hostedZoneId` (to auto-issue + validate one). CloudFront only accepts certs from us-east-1.");if(o!=="us-east-1")throw Error(`serverless app: auto-issuing an asset-domain cert needs a us-east-1 app (CloudFront certs must be us-east-1); this app is in ${o}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);S.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:t.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:t.assetDomain,HostedZoneId:t.hostedZoneId}]}}}if(t.hostedZoneId)S.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:t.hostedZoneId,Name:t.assetDomain,Type:"A",AliasTarget:{DNSName:d.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};E.AssetDomain={Description:"Custom asset CDN host",Value:t.assetDomain}}S.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:d.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:d.sub(`arn:aws:s3:::${T}/*`),Condition:{StringEquals:{"AWS:SourceArn":d.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},E.AssetsBucketName={Description:"Assets bucket",Value:d.ref("AssetsBucket")},E.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:d.getAtt("AssetsDistribution","DomainName")}}if(t.firewall?.enabled){let R=[],x=0;if(t.firewall.rateLimit)R.push({Name:"rate-limit",Priority:x++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:t.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n}-${a}-rate`}});let M={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let V of t.firewall.rules??[]){let me=M[V];if(!me)continue;R.push({Name:`managed-${V}`,Priority:x++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:me}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n}-${a}-${V}`}})}S.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${n}-${a}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:R,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n}-${a}-waf`}}},E.WafAclArn={Description:"WAF web ACL ARN. Attach to a CloudFront distribution fronting the API to enforce (HTTP API v2 stages do not support direct WAF association).",Value:d.getAtt("WebAcl","Arn")}}if(ae&&F){if(!t.vpc?.id)throw Error("serverless app: data services (elasticache / aurora-serverless / rdsProxy / efs) need app.vpc.id (the VPC id) so the managed security group is created in the right VPC.");S.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:t.vpc.id,GroupDescription:`${n}-${a} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(O)S.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${n}-${a}-efs`}]}},j.forEach((R,x)=>{S[`EfsMountTarget${x}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:d.ref("EfsFileSystem"),SubnetId:R,SecurityGroups:[d.getAtt("DataSecurityGroup","GroupId")]}}}),S.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:d.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},E.EfsFileSystemId={Description:"EFS file system id",Value:d.ref("EfsFileSystem")};if(t.cache?.driver==="elasticache")S.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${n}-${a} cache subnets`,SubnetIds:j}},S.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${n}-${a}-cache`,ReplicationGroupDescription:`${n}-${a} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:d.ref("CacheSubnetGroup"),SecurityGroupIds:[d.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},E.CacheEndpoint={Description:"Redis primary endpoint",Value:d.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(t.database?.connection==="aurora-serverless")S.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${n}-${a} db subnets`,SubnetIds:j}},S.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${n}/${a}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},S.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${n}-${a}-db`,DatabaseName:"app",MasterUsername:d.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:d.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:t.database?.minCapacity??0.5,MaxCapacity:t.database?.maxCapacity??4},DBSubnetGroupName:d.ref("DbSubnetGroup"),VpcSecurityGroupIds:[d.getAtt("DataSecurityGroup","GroupId")]}},S.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:d.ref("DbCluster")}},E.DbEndpoint={Description:"Aurora cluster endpoint",Value:d.getAtt("DbCluster","Endpoint.Address")};if(t.rdsProxy&&t.database?.connection==="aurora-serverless")S.DbProxyRole={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"read-db-secret",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:d.ref("DbSecret")}]}}]}},S.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof t.rdsProxy==="object"&&t.rdsProxy.name?t.rdsProxy.name:`${n}-${a}-proxy`,EngineFamily:"MYSQL",RoleArn:d.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:d.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:j,VpcSecurityGroupIds:[d.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},S.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:d.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[d.ref("DbCluster")]}},E.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:d.getAtt("DbProxy","Endpoint")};if(E.HttpFunctionName={Description:"HTTP function name",Value:d.ref("HttpFunction")},E.CliFunctionName={Description:"CLI function name",Value:d.ref("CliFunction")},m)E.QueueFunctionName={Description:"Queue function name",Value:d.ref("QueueFunction")};let $e={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${n}-${a})`,Parameters:g?{ImageUri:{Type:"String",Description:"ECR image URI of the deployment artifact"}}:{ArtifactBucket:{Type:"String",Description:"S3 bucket holding the deployment artifact"},ArtifactKey:{Type:"String",Description:"S3 key of the deployment artifact (zip)"}},Resources:S,Outputs:E},Fe={};for(let R of Object.values(S))Fe[R.Type]=(Fe[R.Type]??0)+1;return{template:$e,functionNames:c,queueNames:u,resourceSummary:Fe}}var Jo=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function Yo(e){let t=`php${e.replace(".","")}`;return Jo.map((a)=>`${t}-php-${a}`)}function dn(e,t){let a=`php${e.replace(".","")}`,r=Yo(e).join(" \\\n "),n=`/opt/remi/${a}/root`,i=`/etc/opt/remi/${a}`;return`${t?`FROM almalinux:9 AS ${t}`:"FROM almalinux:9"}
|
|
7277
7277
|
|
|
7278
7278
|
# Build PHP on AlmaLinux 9 (where Remi's version-isolated SCL packages install
|
|
7279
7279
|
# cleanly — Remi's release RPM rejects Amazon Linux 2023). AlmaLinux 9 shares
|
|
@@ -7313,9 +7313,9 @@ RUN printf 'extension_dir=/opt/php/lib/php/modules\\n' > /opt/php/etc/php.ini &&
|
|
|
7313
7313
|
# Runtime assets (bootstrap, runtime loops, fpm config) are added by the build
|
|
7314
7314
|
# orchestrator after the image is produced. Export /opt as the layer payload.
|
|
7315
7315
|
CMD ["true"]
|
|
7316
|
-
`}function
|
|
7317
|
-
${
|
|
7318
|
-
${
|
|
7316
|
+
`}function Zo(e={}){let t=e.phpVersion??"8.3";return`# ts-cloud PHP ${t} runtime layer (generated) — AWS Lambda provided.al2023.
|
|
7317
|
+
${dn(t)}`}function Jm(e){if(e.kind==="php"){let t=e.phpVersion??"8.3";return`# ts-cloud serverless PHP app image (generated, multi-stage).
|
|
7318
|
+
${dn(t,"phpbuild")}
|
|
7319
7319
|
|
|
7320
7320
|
FROM public.ecr.aws/lambda/provided:al2023
|
|
7321
7321
|
# Bake the relocated PHP runtime from the build stage.
|
|
@@ -7334,7 +7334,7 @@ COPY app/ \${LAMBDA_TASK_ROOT}/
|
|
|
7334
7334
|
|
|
7335
7335
|
# Per-function CMD (e.g. index.http) is supplied via ImageConfig.Command.
|
|
7336
7336
|
CMD [ "index.http" ]
|
|
7337
|
-
`}function
|
|
7337
|
+
`}function hn(){return Xo(ec(import.meta.url))}function yn(){return Rt(ve(hn(),"runtime.mjs"),"utf-8")}function fn(e){return Rt(ve(hn(),`${e}-bootstrap`),"utf-8")}function ap(e){let t=e.architecture??"x86_64",a=t==="arm64"?"arm64":"x64",r=e.version.replace(/^v/,""),n=e.onStep??(()=>{}),i=mn(ve(gn(),"tscloud-node-layer-"));try{let s=r.includes(".")?r:tc(r),o=`node-v${s}-linux-${a}`,c=`https://nodejs.org/dist/v${s}/${o}.tar.xz`;n(`downloading Node ${s} (${t})`);let l=ve(i,"node.tar.xz");Sn(c,l),n("extracting node binary"),It("tar",["-xf",l,"-C",i,`${o}/bin/node`],{stdio:"inherit"});let u=Rt(ve(i,o,"bin","node"));n("packaging layer");let m=[{name:"bootstrap",data:fn("node"),mode:493},{name:"runtime.mjs",data:yn(),mode:420},{name:"bin/node",data:u,mode:493}];return{zip:rt(m),architecture:t,version:s,fileCount:m.length}}finally{pn(i,{recursive:!0,force:!0})}}function rp(e){let t=e.architecture??"x86_64",a=t==="arm64"?"bun-linux-aarch64":"bun-linux-x64",r=e.version==="latest"?"":e.version.replace(/^v/,""),n=e.onStep??(()=>{}),i=mn(ve(gn(),"tscloud-bun-layer-"));try{let s=r?`https://github.com/oven-sh/bun/releases/download/bun-v${r}/${a}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${a}.zip`;n(`downloading Bun ${r||"latest"} (${t})`);let o=ve(i,"bun.zip");Sn(s,o),n("extracting bun binary"),It("unzip",["-o","-q",o,"-d",i],{stdio:"inherit"});let c=Rt(ve(i,a,"bun"));n("packaging layer");let l=[{name:"bootstrap",data:fn("bun"),mode:493},{name:"runtime.mjs",data:yn(),mode:420},{name:"bin/bun",data:c,mode:493}];return{zip:rt(l),architecture:t,version:r||"latest",fileCount:l.length}}finally{pn(i,{recursive:!0,force:!0})}}function Sn(e,t){It("curl",["-fsSL","-o",t,e],{stdio:["ignore","ignore","inherit"]})}function tc(e){let t=It("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),a=JSON.parse(t).find((r)=>r.version.startsWith(`v${e}.`));if(!a)throw Error(`No Node release found for major version ${e}`);return a.version.replace(/^v/,"")}var va="x-ts-cloud-invoke-depth",wa="x-ts-cloud-invoke-chain",Ea="x-ts-cloud-trace-id";function nc(e){return rc("sha256").update(e).digest("hex").slice(0,8)}var ua={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function _t(e,t){if(typeof e.get==="function")return e.get(t)??void 0;let a=e;return a[t]??a[t.toLowerCase()]??a[t.toUpperCase()]}function ic(e,t=64){if(!e)return[];return e.split(".").map((a)=>a.trim()).filter((a)=>/^[0-9a-f]{8}$/.test(a)).slice(-t)}function sc(e,t=ua){let a=nc(e.functionId),r=ic(_t(e.headers,wa)),n=e.traceId??_t(e.headers,Ea)??crypto.randomUUID(),i=[...r,a],s=r.filter((m)=>m===a).length,o=r[r.length-1]===a,c=Number.parseInt(_t(e.headers,va)??"",10),l=Math.max(i.length,Number.isFinite(c)?c+1:0),u="ok";if(l>t.maxDepth)u="depth_exceeded";else if(s>=t.maxRepeats)u="cycle_detected";else if(o&&t.maxRepeats<=1)u="self_invocation";return{reason:u,depth:l,chain:i,traceId:n,selfInvocation:o,repeats:s,propagate:{[va]:String(l),[wa]:i.join("."),[Ea]:n}}}var bn={ok:"",depth_exceeded:"Invocation chain is deeper than the configured limit; the call was refused to stop a runaway loop.",cycle_detected:"This function already appears in the invocation chain; the call was refused as a recursion loop.",self_invocation:"This function invoked itself directly; the call was refused.",trace_budget_exceeded:"This request has already made more invocations than its budget allows.",breaker_open:"Recursion protection is open for this function after repeated loop detections."};class An{limits;clock;traces=new Map;breakers=new Map;constructor(e=ua,t=()=>Date.now()){this.limits=e,this.clock=t}check(e){let t=this.clock();this.expireTraces(t);let a=sc(e,this.limits),r=this.breakers.get(e.functionId);if(r?.openUntil!=null&&r.openUntil>t)return this.deny(e.functionId,a,"breaker_open",t,!1);if(a.reason!=="ok")return this.deny(e.functionId,a,a.reason,t,!0);let n=this.traces.get(a.traceId)??{count:0,firstAt:t};if(n.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(a.traceId,n),this.deny(e.functionId,a,"trace_budget_exceeded",t,!0);if(this.traces.set(a.traceId,{count:n.count+1,firstAt:n.firstAt}),r)this.breakers.set(e.functionId,{consecutiveBlocks:0});return{...a,allowed:!0,reason:"ok",propagate:a.propagate}}deny(e,t,a,r,n){if(n){let i=this.breakers.get(e)??{consecutiveBlocks:0},s=i.consecutiveBlocks+1;this.breakers.set(e,{consecutiveBlocks:s,openUntil:s>=this.limits.breakerThreshold?r+this.limits.breakerCooldownMs:i.openUntil})}return{...t,allowed:!1,reason:a,message:bn[a]}}breakerOpen(e){let t=this.breakers.get(e);return t?.openUntil!=null&&t.openUntil>this.clock()}reset(e){if(e){this.breakers.delete(e);return}this.breakers.clear(),this.traces.clear()}expireTraces(e){if(this.traces.size===0)return;for(let[t,a]of this.traces)if(e-a.firstAt>this.limits.traceWindowMs)this.traces.delete(t)}get trackedTraces(){return this.traces.size}}function oc(e){return{...e.propagate}}function cc(e){return{status:508,headers:{"content-type":"application/json","x-ts-cloud-recursion-blocked":e.reason},body:{error:"recursion_blocked",reason:e.reason,message:e.message??bn[e.reason],depth:e.depth,traceId:e.traceId}}}var Cn=new ac;function Pa(e){let t=globalThis.process?.env?.[e];if(t==null||t==="")return;return t!=="0"&&t.toLowerCase()!=="false"}function lc(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function uc(e){let t=e===!1?{enabled:!1}:e??{},a=Pa("TS_CLOUD_RECURSION_PROTECTION"),r=Pa("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:a??t.enabled??!0,detectionOnly:r??t.detectionOnly??!1,limits:{...ua,...t.limits},functionId:t.functionId??lc()}}var Ne,he;function dc(){let e=globalThis.fetch;if(!e||Ne===e)return()=>{};he=e;let t=async(a,r)=>{let n=Cn.getStore();if(!n)return he(a,r);let i=new Headers(r?.headers??(a instanceof Request?a.headers:void 0));for(let[s,o]of Object.entries(oc(n)))i.set(s,o);if(a instanceof Request)return he(new Request(a,{headers:i}),r);return he(a,{...r,headers:i})};return Object.assign(t,e),globalThis.fetch=t,Ne=t,()=>{if(globalThis.fetch===Ne&&he)globalThis.fetch=he;Ne=void 0}}var gt,Ut;function mc(e){if(!gt||JSON.stringify(Ut)!==JSON.stringify(e))gt=new An(e),Ut=e;return gt}function sp(){if(gt=void 0,Ut=void 0,Ne&&he&&globalThis.fetch===Ne)globalThis.fetch=he;Ne=void 0,he=void 0}function pc(e,t){let a=uc(t);if(!a.enabled)return;let r=mc(a.limits),n={functionId:a.functionId,headers:e},i=r.check(n);return{verdict:i,blocked:!i.allowed&&!a.detectionOnly,observed:!i.allowed&&a.detectionOnly}}function gc(e,t){return dc(),Cn.run(e,t)}function op(e){let t=e,a=t?.default??t;if(typeof a==="function")return{fetch:a};return{fetch:a?.fetch??t?.fetch,queue:a?.queue??t?.queue,cli:a?.cli??t?.cli}}var hc=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function yc(e){if(!e)return!0;return hc.test(e)}function fc(e){if(e?.maintenance)return e.maintenance;let t=globalThis.process?.env??{};return{enabled:t.MAINTENANCE_MODE==="1"||t.MAINTENANCE_MODE==="true",bypassSecret:t.MAINTENANCE_BYPASS_SECRET}}function Sc(e){let t=e.requestContext?.domainName??"localhost",a=e.rawQueryString?`?${e.rawQueryString}`:"",r=`https://${t}${e.rawPath||"/"}${a}`,n=new Headers;for(let[o,c]of Object.entries(e.headers??{}))if(c!==void 0)n.set(o,c);if(e.cookies?.length)n.set("cookie",e.cookies.join("; "));let i=e.requestContext.http.method,s;if(e.body!==void 0&&i!=="GET"&&i!=="HEAD")s=e.isBase64Encoded?new Uint8Array(Buffer.from(e.body,"base64")):new TextEncoder().encode(e.body);return new Request(r,{method:i,headers:n,body:s})}async function Ia(e){let t={},a=[],r=typeof e.headers.getSetCookie==="function"?e.headers.getSetCookie():[];for(let s of r)a.push(s);e.headers.forEach((s,o)=>{if(o.toLowerCase()==="set-cookie")return;t[o]=s});let n=Buffer.from(await e.arrayBuffer()),i=yc(e.headers.get("content-type"));return{statusCode:e.status,headers:t,...a.length?{cookies:a}:{},body:i?n.toString("utf-8"):n.toString("base64"),isBase64Encoded:!i}}function bc(e,t){return async(a)=>{if(a.warmer)return{statusCode:200,headers:{"content-type":"text/plain"},body:"warm",isBase64Encoded:!1};if(!e)return{statusCode:501,headers:{"content-type":"text/plain"},body:"No HTTP handler configured",isBase64Encoded:!1};let r=fc(t);if(r.enabled){let s=a.headers?.["x-maintenance-bypass"]??a.cookies?.find((o)=>o.startsWith("tscloud_bypass="))?.split("=")[1];if(!r.bypassSecret||s!==r.bypassSecret)return{statusCode:503,headers:{"content-type":"text/plain","retry-after":"120"},body:"Service temporarily unavailable (maintenance mode)",isBase64Encoded:!1}}let n=pc(a.headers??{},t?.recursionProtection);if(n?.blocked){let s=cc(n.verdict);return{statusCode:s.status,headers:{...s.headers,"retry-after":"60"},body:JSON.stringify(s.body),isBase64Encoded:!1}}let i=Sc(a);if(!n){let s=await e(i);return Ia(s)}if(n.observed)console.warn(`[ts-cloud] recursion detected (${n.verdict.reason}) at depth ${n.verdict.depth}; detection-only mode let it run`);return gc(n.verdict,async()=>Ia(await e(i)))}}function Ac(e){try{return JSON.parse(e)}catch{return e}}function Cc(e){return async(t)=>{let a=[];if(t.warmer)return{batchItemFailures:a};if(!e)return{batchItemFailures:a};for(let r of t.Records??[])try{await e(Ac(r.body),r)}catch{a.push({itemIdentifier:r.messageId})}return{batchItemFailures:a}}}function Tc(e){return async(t)=>{if(t.warmer)return{statusCode:0,output:"warm"};if(!e)return{statusCode:501,output:"No CLI handler configured"};return e(t)}}function cp(e,t){return{http:bc(e.fetch,t),queue:Cc(e.queue),cli:Tc(e.cli)}}function vc(e={}){let t=e.socketPath??"/tmp/.tscloud-fpm.sock",a=e.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
|
|
7338
7338
|
[global]
|
|
7339
7339
|
daemonize = no
|
|
7340
7340
|
error_log = ${e.errorLog??"/tmp/storage/logs/php-fpm.log"}
|
|
@@ -7351,5 +7351,5 @@ decorate_workers_output = no
|
|
|
7351
7351
|
php_admin_value[error_log] = /dev/stderr
|
|
7352
7352
|
php_admin_flag[log_errors] = on
|
|
7353
7353
|
clear_env = no
|
|
7354
|
-
`}function Pc(){return Cn(wc(Ec(import.meta.url)),"runtime-assets")}function Ia(){let e=Pc(),t=(a)=>vc(Cn(e,a),"utf-8");return[{path:"bootstrap",contents:t("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:t("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:t("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:t("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:t("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:Tc(),mode:420}]}function dp(e={}){let t=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:t,CACHE_DRIVER:t,SESSION_DRIVER:t,QUEUE_CONNECTION:"sqs",FILESYSTEM_DISK:"s3",VIEW_COMPILED_PATH:"/tmp/storage/framework/views",APP_SERVICES_CACHE:"/tmp/bootstrap/cache/services.php",APP_PACKAGES_CACHE:"/tmp/bootstrap/cache/packages.php",APP_CONFIG_CACHE:"/tmp/bootstrap/cache/config.php",APP_ROUTES_CACHE:"/tmp/bootstrap/cache/routes.php",APP_EVENTS_CACHE:"/tmp/bootstrap/cache/events.php"}}var Ic=["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*vn(e){for(let t of kc(e)){let a=Le(e,t);if(Tn(a).isDirectory())yield*vn(a);else yield a}}function yp(e={}){let t=e.architecture??"x86_64",a=e.platform??(t==="arm64"?"linux/arm64":"linux/amd64"),r=e.onStep??(()=>{}),n=Dc(Le(Oc(),"tscloud-php-layer-")),i="tscloud-php-layer:build";try{xc(Le(n,"Dockerfile"),Yo(e)),r("Building PHP runtime image (docker)"),lt("docker",["build","--platform",a,"-t","tscloud-php-layer:build",n],{stdio:"inherit"}),r("Extracting /opt/php from image");let s=lt("docker",["create","--platform",a,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),o=Le(n,"opt");Nc(o,{recursive:!0});try{lt("docker",["cp",`${s}:/opt/php`,Le(o,"php")],{stdio:"inherit"})}finally{lt("docker",["rm",s],{stdio:"ignore"})}if(!Rc(Le(o,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let c=[];for(let m of vn(o)){let p=Wc(o,m).replace(/\\/g,"/"),g=Tn(m).mode&73?493:420;c.push({name:p,data:Mc(m),mode:g})}r("Injecting runtime assets");let l=new Set(Ia().map((m)=>m.path)),u=c.filter((m)=>!l.has(m.name));for(let m of Ia())u.push({name:m.path,data:m.contents,mode:m.mode});return r("Packaging layer ZIP"),{zip:at(u),architecture:t,fileCount:u.length}}finally{Lc(n,{recursive:!0,force:!0})}}var Fc=[".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 jc(e,t){return t.some((a)=>e===a||e.startsWith(`${a}/`))}function*Pn(e,t,a){for(let r of Uc(e)){let n=Vc(e,r),i=En(t,n).replace(/\\/g,"/");if(jc(i,a))continue;if(wn(n).isDirectory())yield*Pn(n,t,a);else yield n}}function Kc(e){if(e.skipBuild)return;let t=ua(e.projectRoot??process.cwd()),a=e.app.build??Ic;for(let r of a)e.onStep?.(`build: ${r}`),_c(r,{stdio:"inherit",cwd:t})}function Hc(e,t=[]){let a=ua(e),r=[...Fc,wt(),...t],n=[];for(let i of Pn(a,a,r)){let s=En(a,i).replace(/\\/g,"/"),o=(wn(i).mode&73)!==0;n.push({name:s,data:Gc(i),mode:o?493:420})}return n}function Cp(e){let t=ua(e.projectRoot??process.cwd());Kc(e),e.onStep?.("packaging application tree");let a=Hc(t,e.exclude);if(!a.length)throw Error(`No files to package under ${t}`);let r=at(a),n=e.app.handlers?.http??"public/index.php";return{zip:r,sha256:Bc("sha256").update(r).digest("hex"),handlers:{http:n,queue:e.app.handlers?.queue??n,cli:e.app.handlers?.cli??n},fileCount:a.length}}class In{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let t=`asset-opt-${Date.now()}-${this.counter++}`,a={id:t,...e};return this.optimizations.set(t,a),a}createImageOptimization(e){let t=`image-opt-${Date.now()}-${this.counter++}`,a={id:t,...e};return this.imageConfigs.set(t,a),a}createSSGConfig(e){let t=`ssg-${Date.now()}-${this.counter++}`,a={id:t,...e};return this.ssgConfigs.set(t,a),a}createPrerenderConfig(e){let t=`prerender-${Date.now()}-${this.counter++}`,a={id:t,...e};return this.prerenderConfigs.set(t,a),a}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 Tp=new In;class Rn{policies=new Map;versioningConfigs=new Map;replicationRules=new Map;tieringConfigs=new Map;objectLocks=new Map;transferAcceleration=new Map;accessPoints=new Map;glacierConfigs=new Map;inventories=new Map;batchOps=new Map;eventNotifications=new Map;counter=0;createLifecyclePolicy(e,t){let a=`lifecycle-${Date.now()}-${this.counter++}`,r={id:a,transitions:e,expiration:t};return this.policies.set(a,r),r}enableVersioning(e=!1){let t=`versioning-${Date.now()}-${this.counter++}`,a={id:t,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(t,a),a}createReplicationRule(e,t,a){let r=`replication-${Date.now()}-${this.counter++}`,n={id:r,sourceRegion:e,destRegion:t,destBucket:a};return this.replicationRules.set(r,n),n}createIntelligentTiering(e,t){let a=`tiering-${Date.now()}-${this.counter++}`,r={id:a,archiveDays:e,deepArchiveDays:t};return this.tieringConfigs.set(a,r),r}enableObjectLock(e){let t=`object-lock-${Date.now()}-${this.counter++}`,a={id:t,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(t,a),a}enableTransferAcceleration(e){let t=`transfer-accel-${Date.now()}-${this.counter++}`,a={id:t,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(t,a),a}createAccessPoint(e){let t=`access-point-${Date.now()}-${this.counter++}`,a={id:t,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(t,a),a}createGlacierArchive(e){let t=`glacier-${Date.now()}-${this.counter++}`,a={id:t,bucketName:e.bucketName,archiveType:e.archiveType,transitionDays:e.transitionDays,restoreConfig:e.restoreTier?{tier:e.restoreTier,days:e.restoreDays||7}:void 0};return this.glacierConfigs.set(t,a),a}createInventory(e){let t=`inventory-${Date.now()}-${this.counter++}`,a={id:t,sourceBucket:e.sourceBucket,destinationBucket:e.destinationBucket,schedule:e.schedule||"Daily",format:e.format||"CSV",includedFields:e.includedFields||["Size","LastModifiedDate","StorageClass","ETag"],prefix:e.prefix};return this.inventories.set(t,a),a}createBatchOperation(e){let t=`batch-op-${Date.now()}-${this.counter++}`,a={id:t,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(t,a),a}executeBatchOperation(e){let t=this.batchOps.get(e);if(!t)throw Error(`Batch operation not found: ${e}`);return t.status="in_progress",t.totalObjects=1000,t.processedObjects=0,t}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let t=`event-${Date.now()}-${this.counter++}`,a={id:t,bucketName:e.bucketName,events:e.events,destination:{type:"Lambda",arn:e.lambdaArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(t,a),a}createSQSNotification(e){let t=`event-${Date.now()}-${this.counter++}`,a={id:t,bucketName:e.bucketName,events:e.events,destination:{type:"SQS",arn:e.queueArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(t,a),a}createSNSNotification(e){let t=`event-${Date.now()}-${this.counter++}`,a={id:t,bucketName:e.bucketName,events:e.events,destination:{type:"SNS",arn:e.topicArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(t,a),a}generateObjectLockCF(e){let t={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)t.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)t.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return t}generateTransferAccelerationCF(e){return{AccelerateConfiguration:{AccelerationStatus:e.enabled?"Enabled":"Suspended"}}}generateAccessPointCF(e){return{Type:"AWS::S3::AccessPoint",Properties:{Name:e.name,Bucket:e.bucketName,...e.vpcId&&{VpcConfiguration:{VpcId:e.vpcId}},PublicAccessBlockConfiguration:e.publicAccessBlock?{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}:void 0,...e.policy&&{Policy:e.policy}}}}generateInventoryCF(e){return{Type:"AWS::S3::Bucket",Properties:{InventoryConfigurations:[{Id:e.id,Destination:{BucketArn:`arn:aws:s3:::${e.destinationBucket}`,Format:e.format},Enabled:!0,IncludedObjectVersions:"Current",OptionalFields:e.includedFields,ScheduleFrequency:e.schedule,...e.prefix&&{Prefix:e.prefix}}]}}}generateEventNotificationCF(e){let t=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",a=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",r={Event:e.events[0],[a]:e.destination.arn};if(e.filter)r.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[t]:[r]}}}clear(){this.policies.clear(),this.versioningConfigs.clear(),this.replicationRules.clear(),this.tieringConfigs.clear(),this.objectLocks.clear(),this.transferAcceleration.clear(),this.accessPoints.clear(),this.glacierConfigs.clear(),this.inventories.clear(),this.batchOps.clear(),this.eventNotifications.clear()}}var vp=new Rn;class Nn{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,t=30,a=10){let r=`health-${Date.now()}-${this.counter++}`,n={id:r,url:e,interval:t,timeout:a,status:"healthy"};return this.checks.set(r,n),n}createSyntheticMonitor(e,t,a,r){let n=`synthetic-${Date.now()}-${this.counter++}`,i={id:n,name:e,script:t,frequency:a,locations:r};return this.synthetics.set(n,i),i}trackUptime(e,t,a){let r=`uptime-${Date.now()}-${this.counter++}`,n=t/(t+a)*100,i={id:r,resource:e,uptime:t,downtime:a,availability:n};return this.uptimeTrackers.set(r,i),i}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var wp=new Nn;class Dn{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,t,a,r){let n=`waf-${Date.now()}-${this.counter++}`,i={id:n,name:e,priority:t,action:a,conditions:r};return this.wafRules.set(n,i),i}enableShield(e,t="standard"){let a=`shield-${Date.now()}-${this.counter++}`,r={id:a,resourceArn:e,protectionType:t};return this.shieldProtections.set(a,r),r}createSecurityGroup(e,t,a){let r=`sg-${Date.now()}-${this.counter++}`,n={id:r,name:e,vpcId:t,rules:a};return this.securityGroups.set(r,n),n}createNACL(e,t){let a=`nacl-${Date.now()}-${this.counter++}`,r={id:a,vpcId:e,rules:t};return this.nacls.set(a,r),r}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var Ep=new Dn;class kn{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,t){let a=`tagging-${Date.now()}-${this.counter++}`,r={id:a,tags:e,resources:t};return this.strategies.set(a,r),r}createCostAllocation(e,t){let a=`cost-${Date.now()}-${this.counter++}`,r={id:a,tagKey:e,allocations:t};return this.allocations.set(a,r),r}createResourceGroup(e,t,a){let r=`group-${Date.now()}-${this.counter++}`,n={id:r,name:e,query:{resourceTypeFilters:t,tagFilters:a}};return this.groups.set(r,n),n}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var Pp=new kn;
|
|
7355
|
-
export{jt as Bl,K as Cl,Kt as Dl,
|
|
7354
|
+
`}function Ic(){return Tn(Ec(Pc(import.meta.url)),"runtime-assets")}function Ra(){let e=Ic(),t=(a)=>wc(Tn(e,a),"utf-8");return[{path:"bootstrap",contents:t("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:t("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:t("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:t("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:t("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:vc(),mode:420}]}function mp(e={}){let t=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:t,CACHE_DRIVER:t,SESSION_DRIVER:t,QUEUE_CONNECTION:"sqs",FILESYSTEM_DISK:"s3",VIEW_COMPILED_PATH:"/tmp/storage/framework/views",APP_SERVICES_CACHE:"/tmp/bootstrap/cache/services.php",APP_PACKAGES_CACHE:"/tmp/bootstrap/cache/packages.php",APP_CONFIG_CACHE:"/tmp/bootstrap/cache/config.php",APP_ROUTES_CACHE:"/tmp/bootstrap/cache/routes.php",APP_EVENTS_CACHE:"/tmp/bootstrap/cache/events.php"}}var Rc=["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*wn(e){for(let t of $c(e)){let a=Me(e,t);if(vn(a).isDirectory())yield*wn(a);else yield a}}function fp(e={}){let t=e.architecture??"x86_64",a=e.platform??(t==="arm64"?"linux/arm64":"linux/amd64"),r=e.onStep??(()=>{}),n=kc(Me(Oc(),"tscloud-php-layer-")),i="tscloud-php-layer:build";try{xc(Me(n,"Dockerfile"),Zo(e)),r("Building PHP runtime image (docker)"),ut("docker",["build","--platform",a,"-t","tscloud-php-layer:build",n],{stdio:"inherit"}),r("Extracting /opt/php from image");let s=ut("docker",["create","--platform",a,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),o=Me(n,"opt");Dc(o,{recursive:!0});try{ut("docker",["cp",`${s}:/opt/php`,Me(o,"php")],{stdio:"inherit"})}finally{ut("docker",["rm",s],{stdio:"ignore"})}if(!Nc(Me(o,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let c=[];for(let m of wn(o)){let p=Bc(o,m).replace(/\\/g,"/"),g=vn(m).mode&73?493:420;c.push({name:p,data:Lc(m),mode:g})}r("Injecting runtime assets");let l=new Set(Ra().map((m)=>m.path)),u=c.filter((m)=>!l.has(m.name));for(let m of Ra())u.push({name:m.path,data:m.contents,mode:m.mode});return r("Packaging layer ZIP"),{zip:rt(u),architecture:t,fileCount:u.length}}finally{Mc(n,{recursive:!0,force:!0})}}var Uc=[".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 jc(e,t){return t.some((a)=>e===a||e.startsWith(`${a}/`))}function*In(e,t,a){for(let r of Gc(e)){let n=Vc(e,r),i=Pn(t,n).replace(/\\/g,"/");if(jc(i,a))continue;if(En(n).isDirectory())yield*In(n,t,a);else yield n}}function Kc(e){if(e.skipBuild)return;let t=da(e.projectRoot??process.cwd()),a=e.app.build??Rc;for(let r of a)e.onStep?.(`build: ${r}`),_c(r,{stdio:"inherit",cwd:t})}function Hc(e,t=[]){let a=da(e),r=[...Uc,Et(),...t],n=[];for(let i of In(a,a,r)){let s=Pn(a,i).replace(/\\/g,"/"),o=(En(i).mode&73)!==0;n.push({name:s,data:Fc(i),mode:o?493:420})}return n}function Tp(e){let t=da(e.projectRoot??process.cwd());Kc(e),e.onStep?.("packaging application tree");let a=Hc(t,e.exclude);if(!a.length)throw Error(`No files to package under ${t}`);let r=rt(a),n=e.app.handlers?.http??"public/index.php";return{zip:r,sha256:Wc("sha256").update(r).digest("hex"),handlers:{http:n,queue:e.app.handlers?.queue??n,cli:e.app.handlers?.cli??n},fileCount:a.length}}class Rn{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let t=`asset-opt-${Date.now()}-${this.counter++}`,a={id:t,...e};return this.optimizations.set(t,a),a}createImageOptimization(e){let t=`image-opt-${Date.now()}-${this.counter++}`,a={id:t,...e};return this.imageConfigs.set(t,a),a}createSSGConfig(e){let t=`ssg-${Date.now()}-${this.counter++}`,a={id:t,...e};return this.ssgConfigs.set(t,a),a}createPrerenderConfig(e){let t=`prerender-${Date.now()}-${this.counter++}`,a={id:t,...e};return this.prerenderConfigs.set(t,a),a}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 vp=new Rn;class Nn{policies=new Map;versioningConfigs=new Map;replicationRules=new Map;tieringConfigs=new Map;objectLocks=new Map;transferAcceleration=new Map;accessPoints=new Map;glacierConfigs=new Map;inventories=new Map;batchOps=new Map;eventNotifications=new Map;counter=0;createLifecyclePolicy(e,t){let a=`lifecycle-${Date.now()}-${this.counter++}`,r={id:a,transitions:e,expiration:t};return this.policies.set(a,r),r}enableVersioning(e=!1){let t=`versioning-${Date.now()}-${this.counter++}`,a={id:t,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(t,a),a}createReplicationRule(e,t,a){let r=`replication-${Date.now()}-${this.counter++}`,n={id:r,sourceRegion:e,destRegion:t,destBucket:a};return this.replicationRules.set(r,n),n}createIntelligentTiering(e,t){let a=`tiering-${Date.now()}-${this.counter++}`,r={id:a,archiveDays:e,deepArchiveDays:t};return this.tieringConfigs.set(a,r),r}enableObjectLock(e){let t=`object-lock-${Date.now()}-${this.counter++}`,a={id:t,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(t,a),a}enableTransferAcceleration(e){let t=`transfer-accel-${Date.now()}-${this.counter++}`,a={id:t,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(t,a),a}createAccessPoint(e){let t=`access-point-${Date.now()}-${this.counter++}`,a={id:t,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(t,a),a}createGlacierArchive(e){let t=`glacier-${Date.now()}-${this.counter++}`,a={id:t,bucketName:e.bucketName,archiveType:e.archiveType,transitionDays:e.transitionDays,restoreConfig:e.restoreTier?{tier:e.restoreTier,days:e.restoreDays||7}:void 0};return this.glacierConfigs.set(t,a),a}createInventory(e){let t=`inventory-${Date.now()}-${this.counter++}`,a={id:t,sourceBucket:e.sourceBucket,destinationBucket:e.destinationBucket,schedule:e.schedule||"Daily",format:e.format||"CSV",includedFields:e.includedFields||["Size","LastModifiedDate","StorageClass","ETag"],prefix:e.prefix};return this.inventories.set(t,a),a}createBatchOperation(e){let t=`batch-op-${Date.now()}-${this.counter++}`,a={id:t,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(t,a),a}executeBatchOperation(e){let t=this.batchOps.get(e);if(!t)throw Error(`Batch operation not found: ${e}`);return t.status="in_progress",t.totalObjects=1000,t.processedObjects=0,t}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let t=`event-${Date.now()}-${this.counter++}`,a={id:t,bucketName:e.bucketName,events:e.events,destination:{type:"Lambda",arn:e.lambdaArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(t,a),a}createSQSNotification(e){let t=`event-${Date.now()}-${this.counter++}`,a={id:t,bucketName:e.bucketName,events:e.events,destination:{type:"SQS",arn:e.queueArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(t,a),a}createSNSNotification(e){let t=`event-${Date.now()}-${this.counter++}`,a={id:t,bucketName:e.bucketName,events:e.events,destination:{type:"SNS",arn:e.topicArn},filter:e.prefix||e.suffix?{prefix:e.prefix,suffix:e.suffix}:void 0};return this.eventNotifications.set(t,a),a}generateObjectLockCF(e){let t={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)t.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)t.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return t}generateTransferAccelerationCF(e){return{AccelerateConfiguration:{AccelerationStatus:e.enabled?"Enabled":"Suspended"}}}generateAccessPointCF(e){return{Type:"AWS::S3::AccessPoint",Properties:{Name:e.name,Bucket:e.bucketName,...e.vpcId&&{VpcConfiguration:{VpcId:e.vpcId}},PublicAccessBlockConfiguration:e.publicAccessBlock?{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}:void 0,...e.policy&&{Policy:e.policy}}}}generateInventoryCF(e){return{Type:"AWS::S3::Bucket",Properties:{InventoryConfigurations:[{Id:e.id,Destination:{BucketArn:`arn:aws:s3:::${e.destinationBucket}`,Format:e.format},Enabled:!0,IncludedObjectVersions:"Current",OptionalFields:e.includedFields,ScheduleFrequency:e.schedule,...e.prefix&&{Prefix:e.prefix}}]}}}generateEventNotificationCF(e){let t=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",a=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",r={Event:e.events[0],[a]:e.destination.arn};if(e.filter)r.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[t]:[r]}}}clear(){this.policies.clear(),this.versioningConfigs.clear(),this.replicationRules.clear(),this.tieringConfigs.clear(),this.objectLocks.clear(),this.transferAcceleration.clear(),this.accessPoints.clear(),this.glacierConfigs.clear(),this.inventories.clear(),this.batchOps.clear(),this.eventNotifications.clear()}}var wp=new Nn;class Dn{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,t=30,a=10){let r=`health-${Date.now()}-${this.counter++}`,n={id:r,url:e,interval:t,timeout:a,status:"healthy"};return this.checks.set(r,n),n}createSyntheticMonitor(e,t,a,r){let n=`synthetic-${Date.now()}-${this.counter++}`,i={id:n,name:e,script:t,frequency:a,locations:r};return this.synthetics.set(n,i),i}trackUptime(e,t,a){let r=`uptime-${Date.now()}-${this.counter++}`,n=t/(t+a)*100,i={id:r,resource:e,uptime:t,downtime:a,availability:n};return this.uptimeTrackers.set(r,i),i}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var Ep=new Dn;class kn{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,t,a,r){let n=`waf-${Date.now()}-${this.counter++}`,i={id:n,name:e,priority:t,action:a,conditions:r};return this.wafRules.set(n,i),i}enableShield(e,t="standard"){let a=`shield-${Date.now()}-${this.counter++}`,r={id:a,resourceArn:e,protectionType:t};return this.shieldProtections.set(a,r),r}createSecurityGroup(e,t,a){let r=`sg-${Date.now()}-${this.counter++}`,n={id:r,name:e,vpcId:t,rules:a};return this.securityGroups.set(r,n),n}createNACL(e,t){let a=`nacl-${Date.now()}-${this.counter++}`,r={id:a,vpcId:e,rules:t};return this.nacls.set(a,r),r}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var Pp=new kn;class $n{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,t){let a=`tagging-${Date.now()}-${this.counter++}`,r={id:a,tags:e,resources:t};return this.strategies.set(a,r),r}createCostAllocation(e,t){let a=`cost-${Date.now()}-${this.counter++}`,r={id:a,tagKey:e,allocations:t};return this.allocations.set(a,r),r}createResourceGroup(e,t,a){let r=`group-${Date.now()}-${this.counter++}`,n={id:r,name:e,query:{resourceTypeFilters:t,tagFilters:a}};return this.groups.set(r,n),n}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var Ip=new $n;
|
|
7355
|
+
export{jt as Bl,K as Cl,Kt as Dl,Da as El,Fn as Fl,Ba as Gl,Vn as Hl,Un as Il,jn as Jl,Kn as Kl,Hn as Ll,qn as Ml,zn as Nl,Qn as Ol,zc as Pl,Qc as Ql,Ga as Rl,Yn as Sl,Yc as Tl,Et as Ul,Zn as Vl,Xn as Wl,Zc as Xl,Va as Yl,Xc as Zl,el as _l,tl as $l,ti as am,al as bm,rl as cm,nl as dm,il as em,ni as fm,sl as gm,A as hm,f as im,ol as jm,cl as km,ll as lm,ul as mm,dl as nm,ml as om,pl as pm,gl as qm,hl as rm,yl as sm,ii as tm,si as um,fl as vm,Sl as wm,Pe as xm,pe as ym,ne as zm,q as Am,G as Bm,k as Cm,B as Dm,qe as Em,_ as Fm,ui as Gm,ge as Hm,se as Im,Te as Jm,Cl as Km,yi as Lm,z as Mm,vi as Nm,dt as Om,Ft as Pm,wi as Qm,ie as Rm,Ei as Sm,ee as Tm,Pi as Um,Ha as Vm,Q as Wm,J as Xm,U as Ym,ze as Zm,W as _m,Qe as $m,mt as an,Y as bn,d as cn,bt as dn,El as en,qa as fn,Pl as gn,Il as hn,Rl as in,Nl as jn,Dl as kn,kl as ln,$l as mn,Ll as nn,Ml as on,xl as pn,Ol as qn,Bl as rn,_l as sn,Wl as tn,Gl as un,Fl as vn,Vl as wn,Ul as xn,ys as yn,fs as zn,As as An,Cs as Bn,Ts as Cn,vs as Dn,ws as En,Es as Fn,Ja as Gn,ya as Hn,Ps as In,Is as Jn,jl as Kn,fa as Ln,Kl as Mn,Hl as Nn,We as On,ql as Pn,zl as Qn,Ql as Rn,Jl as Sn,Yl as Tn,Zl as Un,Rs as Vn,Ns as Wn,ks as Xn,$s as Yn,Ls as Zn,Pt as _n,au as $n,Ms as ao,xs as bo,Os as co,Z as do,ru as eo,fe as fo,pt as go,Ie as ho,Vs as io,tr as jo,Us as ko,js as lo,Ks as mo,ba as no,te as oo,nu as po,iu as qo,su as ro,ou as so,Hs as to,cu as uo,H as vo,lu as wo,uu as xo,du as yo,rr as zo,nr as Ao,hu as Bo,ir as Co,sr as Do,bu as Eo,Au as Fo,Cu as Go,Tu as Ho,vu as Io,Xs as Jo,Jt as Ko,wu as Lo,Eu as Mo,Pu as No,Iu as Oo,Ru as Po,eo as Qo,to as Ro,Nu as So,Du as To,ku as Uo,$u as Vo,Lu as Wo,Mu as Xo,xu as Yo,Ou as Zo,Bu as _o,cr as $o,Yt as ap,_u as bp,Wu as cp,Gu as dp,Fu as ep,lr as fp,ur as gp,dr as hp,Vu as ip,mr as jp,Uu as kp,ju as lp,Ku as mp,Hu as np,pr as op,qu as pp,zu as qp,Qu as rp,Ju as sp,Yu as tp,Zu as up,Xu as vp,ed as wp,io as xp,so as yp,oo as zp,co as Ap,hr as Bp,td as Cp,ad as Dp,rd as Ep,nd as Fp,id as Gp,sd as Hp,od as Ip,cd as Jp,ld as Kp,mo as Lp,po as Mp,go as Np,ho as Op,ud as Pp,dd as Qp,yr as Rp,md as Sp,fr as Tp,Sr as Up,br as Vp,Ar as Wp,pd as Xp,gd as Yp,hd as Zp,yd as _p,oe as $p,Ye as aq,fd as bq,Sd as cq,bd as dq,Ad as eq,Cd as fq,Td as gq,vd as hq,wd as iq,So as jq,Ed as kq,Pd as lq,Cr as mq,Tr as nq,Id as oq,Rd as pq,bo as qq,Nd as rq,Dd as sq,kd as tq,$d as uq,Ld as vq,Md as wq,xd as xq,Od as yq,Bd as zq,_d as Aq,Wd as Bq,Gd as Cq,Fd as Dq,Vd as Eq,Ud as Fq,jd as Gq,Kd as Hq,Hd as Iq,qd as Jq,zd as Kq,Qd as Lq,vr as Mq,Jd as Nq,wr as Oq,Yd as Pq,Er as Qq,Zd as Rq,Pr as Sq,Xd as Tq,Ir as Uq,em as Vq,xe as Wq,tm as Xq,Rr as Yq,am as Zq,Ct as _q,rm as $q,Nr as ar,nm as br,Dr as cr,im as dr,kr as er,sm as fr,$r as gr,om as hr,Lr as ir,cm as jr,Oe as kr,lm as lr,Mr as mr,um as nr,xr as or,dm as pr,Or as qr,mm as rr,Br as sr,pm as tr,_r as ur,gm as vr,Wr as wr,hm as xr,Gr as yr,ym as zr,Fr as Ar,fm as Br,Vr as Cr,Sm as Dr,Ur as Er,bm as Fr,jr as Gr,Am as Hr,Kr as Ir,Cm as Jr,Hr as Kr,Tm as Lr,qr as Mr,vm as Nr,zr as Or,wm as Pr,Qr,Em as Rr,Jr as Sr,Pm as Tr,Yr as Ur,Im as Vr,Zr as Wr,Rm as Xr,Xr as Yr,Nm as Zr,en as _r,Dm as $r,tn as as,km as bs,an as cs,$m as ds,rn as es,Lm as fs,nn as gs,Mm as hs,Ao as is,Co as js,wo as ks,Eo as ls,sn as ms,xm as ns,on as os,Om as ps,cn as qs,Bm as rs,ln as ss,_m as ts,rt as us,ko as vs,Ko as ws,Ho as xs,Hm as ys,qm as zs,qo as As,Qo as Bs,un as Cs,zm as Ds,Qm as Es,Jo as Fs,Yo as Gs,dn as Hs,Zo as Is,Jm as Js,yn as Ks,ap as Ls,rp as Ms,va as Ns,wa as Os,Ea as Ps,nc as Qs,ua as Rs,ic as Ss,sc as Ts,An as Us,oc as Vs,cc as Ws,Cn as Xs,uc as Ys,dc as Zs,mc as _s,sp as $s,pc as at,gc as bt,op as ct,Sc as dt,Ia as et,bc as ft,Cc as gt,Tc as ht,cp as it,vc as jt,Ra as kt,mp as lt,Rc as mt,fp as nt,Uc as ot,Kc as pt,Hc as qt,Tp as rt,Rn as st,vp as tt,Nn as ut,wp as vt,Dn as wt,Ep as xt,kn as yt,Pp as zt,$n as At,Ip as Bt};
|