@stacksjs/ts-cloud 0.16.89 → 0.16.91
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/client.d.ts +3 -5
- package/dist/aws/credentials.d.ts +9 -4
- package/dist/aws/index.js +1 -1
- package/dist/bin/chunk-0b6rv9dt.js +1 -0
- package/dist/bin/chunk-0qzt0swj.js +5 -0
- package/dist/bin/chunk-0rvzy2z7.js +1 -0
- package/dist/bin/{chunk-z9g7fa1w.js → chunk-0zepgwq9.js} +2 -2
- package/dist/bin/chunk-11hc309t.js +1 -0
- package/dist/bin/{chunk-qmwqntnx.js → chunk-1p7rtk98.js} +2 -2
- package/dist/bin/{chunk-qpasspad.js → chunk-32dr1fym.js} +5 -5
- package/dist/bin/{chunk-v3trt4q1.js → chunk-3h7gmatb.js} +3 -3
- package/dist/bin/{chunk-69mejej3.js → chunk-407wz1f4.js} +1 -1
- package/dist/bin/{chunk-xycxw00z.js → chunk-42nh9ac7.js} +8 -8
- package/dist/bin/chunk-49zcdbn0.js +1 -0
- package/dist/bin/chunk-4gv5j5s1.js +1 -0
- package/dist/bin/{chunk-gn7rdyz7.js → chunk-4kka906v.js} +2 -2
- package/dist/bin/{chunk-jqs2ywj2.js → chunk-55mv5w3m.js} +2 -2
- package/dist/bin/{chunk-4mep3m41.js → chunk-57yxbyh6.js} +5 -5
- package/dist/bin/chunk-5nfhjr0h.js +1 -0
- package/dist/bin/chunk-5njr2s5x.js +1 -0
- package/dist/bin/chunk-6qhgzf9a.js +1 -0
- package/dist/bin/{chunk-bycbwddj.js → chunk-6ty1wegm.js} +2 -2
- package/dist/bin/chunk-8ctmc30y.js +14 -0
- package/dist/bin/{chunk-deptcjq9.js → chunk-97j6xrfe.js} +97 -97
- package/dist/bin/chunk-9g4qsx30.js +1 -0
- package/dist/bin/chunk-afvk9mbs.js +1 -0
- package/dist/bin/{chunk-9bmaq8q7.js → chunk-cb0yqrpk.js} +111 -113
- package/dist/bin/{chunk-bxks81wn.js → chunk-chx779q9.js} +3 -3
- package/dist/bin/chunk-ckbv6y4c.js +1 -0
- package/dist/bin/{chunk-6b6yr784.js → chunk-drc9y2fj.js} +2 -2
- package/dist/bin/{chunk-b1cb27m8.js → chunk-eqqqbsjm.js} +7 -7
- package/dist/bin/{chunk-cgyk48s5.js → chunk-fcst782q.js} +1 -1
- package/dist/bin/{chunk-19mhwmfp.js → chunk-fmgv99xw.js} +1 -1
- package/dist/bin/{chunk-0e56zmps.js → chunk-g1s5s95g.js} +2 -2
- package/dist/bin/{chunk-h6xne9s6.js → chunk-g21yhm1b.js} +96 -96
- package/dist/bin/{chunk-ye2gymsr.js → chunk-gkgqss71.js} +3 -3
- package/dist/bin/chunk-gvacnz2y.js +1 -0
- package/dist/bin/{chunk-em9swj0k.js → chunk-h99kxww0.js} +1 -1
- package/dist/bin/chunk-j1dbkpha.js +1 -0
- package/dist/bin/{chunk-zfn3a9sx.js → chunk-j34ask5s.js} +2 -2
- package/dist/bin/{chunk-f7jzs1h1.js → chunk-j7j7gffr.js} +5 -5
- package/dist/bin/chunk-jjw5d8b9.js +1 -0
- package/dist/bin/{chunk-1wgyq50e.js → chunk-kbtx3q9m.js} +29 -30
- package/dist/bin/{chunk-t0r1rdj2.js → chunk-kdjrcvr6.js} +2 -2
- package/dist/bin/{chunk-76ekkat8.js → chunk-kefwtr8r.js} +3 -3
- package/dist/bin/{chunk-v1a0b9yq.js → chunk-kp84kged.js} +16 -16
- package/dist/bin/chunk-m5tpfe3s.js +1 -0
- package/dist/bin/{chunk-83tt2t15.js → chunk-mrkrn8dk.js} +5 -5
- package/dist/bin/chunk-n6yvpj86.js +1 -0
- package/dist/bin/{chunk-bkx2kapc.js → chunk-ncj8dpdp.js} +2 -2
- package/dist/bin/{chunk-w40r35vn.js → chunk-p6swcv5y.js} +1 -1
- package/dist/bin/{chunk-ndvma07s.js → chunk-pat56kbr.js} +5 -5
- package/dist/bin/chunk-q2hg6hmg.js +1 -0
- package/dist/bin/chunk-qd1jfsam.js +1 -0
- package/dist/bin/{chunk-yf2drw7r.js → chunk-r1q343bm.js} +1 -1
- package/dist/bin/chunk-r50x03ws.js +1 -0
- package/dist/bin/chunk-rhncmffy.js +1 -0
- package/dist/bin/chunk-seh19g93.js +1 -0
- package/dist/bin/{chunk-35325988.js → chunk-sjzzx539.js} +2 -2
- package/dist/bin/chunk-sxfdxk39.js +1 -0
- package/dist/bin/chunk-ty2pdbz3.js +1 -0
- package/dist/bin/chunk-tyeessz3.js +1 -0
- package/dist/bin/chunk-vbsk8b9d.js +1 -0
- package/dist/bin/chunk-we82q71y.js +1 -0
- package/dist/bin/{chunk-zn9wmqd1.js → chunk-xhqfha32.js} +2 -2
- package/dist/bin/{chunk-89v3ec9n.js → chunk-xk8nrvjz.js} +1 -1
- package/dist/bin/{chunk-88s5w4yt.js → chunk-zpk7fn1s.js} +6 -6
- package/dist/bin/cli.js +216 -216
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/bin/stacks-queue-worker.js +1 -1
- package/dist/bin/stacks-scheduler.js +1 -1
- package/dist/chunk-0v77443p.js +1 -0
- package/dist/{chunk-z56sccfh.js → chunk-1087xz1v.js} +2 -2
- package/dist/{chunk-c8kf2268.js → chunk-1psh3mhm.js} +29 -30
- package/dist/chunk-4khjjgd3.js +1 -0
- package/dist/{chunk-4pztf7ws.js → chunk-4m5gpp6w.js} +5 -5
- package/dist/{chunk-3bvhthfb.js → chunk-72p2tdpe.js} +115 -117
- package/dist/chunk-7d9ek8rc.js +5 -0
- package/dist/chunk-872fdms3.js +1 -0
- package/dist/{chunk-cq079p4a.js → chunk-9f18pebj.js} +6 -6
- package/dist/{chunk-vq8bejep.js → chunk-a77mhcs7.js} +3 -3
- package/dist/chunk-bazah9w0.js +1 -0
- package/dist/{chunk-tmp2ym80.js → chunk-by7hejhg.js} +1 -1
- package/dist/{chunk-ax320pn8.js → chunk-byr76jcy.js} +19 -19
- package/dist/{chunk-m35z9vyn.js → chunk-c6kb5c5v.js} +4 -4
- package/dist/{chunk-gpgmp9dt.js → chunk-dmv3vryr.js} +10 -10
- package/dist/{chunk-5t92a838.js → chunk-fe6m7wb0.js} +45 -45
- package/dist/{chunk-py8dq1ey.js → chunk-fne338jr.js} +5 -5
- package/dist/{chunk-nftqsker.js → chunk-h6kptkce.js} +2 -2
- package/dist/{chunk-fdf181e6.js → chunk-hcbrgyfz.js} +2 -2
- package/dist/{chunk-9pwvnh3f.js → chunk-jz6dacx1.js} +2 -2
- package/dist/{chunk-fjs0wgyw.js → chunk-kcem6dzk.js} +2 -2
- package/dist/{chunk-7xy7bsyx.js → chunk-mvmxy0z7.js} +110 -110
- package/dist/{chunk-bvywngfv.js → chunk-n95wbpge.js} +136 -136
- package/dist/{chunk-4ccv5c4m.js → chunk-q7yf28cc.js} +1 -1
- package/dist/{chunk-jx1zz1pw.js → chunk-qra9k26f.js} +1 -1
- package/dist/chunk-qs7814ya.js +1 -0
- package/dist/chunk-sd5a61c6.js +1 -0
- package/dist/{bin/chunk-8rkfwgb4.js → chunk-sjfc9my3.js} +7 -7
- package/dist/{chunk-84z2a1xn.js → chunk-sxqe8e9c.js} +7 -7
- package/dist/{chunk-g0bh9atv.js → chunk-t1wq0ckc.js} +2 -2
- package/dist/{chunk-c71hhcsb.js → chunk-tpvmpmxj.js} +1 -1
- package/dist/{chunk-tr54e9c0.js → chunk-x7cnfn7y.js} +2 -2
- package/dist/{chunk-fpad8xw9.js → chunk-xs9m0v31.js} +4 -4
- package/dist/chunk-zft558kj.js +1 -0
- package/dist/{chunk-e75dvdqf.js → chunk-zwayp7fz.js} +2 -2
- package/dist/{chunk-gdw52mn4.js → chunk-zy3kr4s2.js} +3 -3
- package/dist/deploy/index.js +1 -1
- package/dist/dns/index.js +1 -1
- package/dist/drivers/index.js +1 -1
- package/dist/index.js +31 -31
- package/dist/mail/index.js +2 -2
- package/dist/operations/index.js +1 -1
- package/dist/protection/index.js +1 -1
- package/dist/spend/index.js +1 -1
- package/dist/ui/404.html +1 -1
- package/dist/ui/accept-invitation.html +1 -1
- package/dist/ui/access-denied.html +1 -1
- package/dist/ui/account/automation.html +6 -6
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +6 -6
- package/dist/ui/applications/new.html +2 -2
- package/dist/ui/data/backups.html +5 -5
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +6 -6
- package/dist/ui/integrations.html +1 -1
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +6 -6
- package/dist/ui/operations/jobs.html +6 -6
- package/dist/ui/operations/maintenance.html +5 -5
- package/dist/ui/operations/observability.html +5 -5
- package/dist/ui/operations/previews.html +5 -5
- package/dist/ui/operations/queue.html +5 -5
- package/dist/ui/operations/regions.html +5 -5
- package/dist/ui/operations/releases.html +5 -5
- package/dist/ui/operations/spend.html +6 -6
- package/dist/ui/operations/workloads.html +6 -6
- package/dist/ui/security.html +1 -1
- package/dist/ui/server/actions.html +6 -6
- package/dist/ui/server/activity.html +1 -1
- package/dist/ui/server/capacity.html +6 -6
- package/dist/ui/server/database.html +6 -6
- package/dist/ui/server/deployments.html +6 -6
- package/dist/ui/server/diagnostics.html +2 -2
- package/dist/ui/server/firewall.html +6 -6
- package/dist/ui/server/fleet.html +6 -6
- package/dist/ui/server/logs.html +6 -6
- package/dist/ui/server/metrics.html +6 -6
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +1 -1
- package/dist/ui/server/sites.html +6 -6
- package/dist/ui/server/ssh-keys.html +6 -6
- package/dist/ui/server/team.html +5 -5
- package/dist/ui/server/terminal.html +2 -2
- package/dist/ui/serverless/alarms.html +6 -6
- package/dist/ui/serverless/assets.html +2 -2
- package/dist/ui/serverless/cost.html +2 -2
- package/dist/ui/serverless/data.html +6 -6
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +2 -2
- package/dist/ui/serverless/functions.html +6 -6
- package/dist/ui/serverless/logs.html +6 -6
- package/dist/ui/serverless/metrics.html +2 -2
- package/dist/ui/serverless/queues.html +6 -6
- package/dist/ui/serverless/secrets.html +6 -6
- package/dist/ui/serverless/traces.html +6 -6
- package/dist/ui/serverless.html +5 -5
- package/package.json +3 -3
- package/dist/bin/chunk-1qez75tb.js +0 -1
- package/dist/bin/chunk-1rrmswhq.js +0 -1
- package/dist/bin/chunk-1vw6khps.js +0 -1
- package/dist/bin/chunk-2h1q758c.js +0 -2
- package/dist/bin/chunk-3rjer1mp.js +0 -1
- package/dist/bin/chunk-4k2x5x3k.js +0 -1
- package/dist/bin/chunk-5tzygzdy.js +0 -1
- package/dist/bin/chunk-6wvjr3ne.js +0 -1
- package/dist/bin/chunk-71fa7yed.js +0 -1
- package/dist/bin/chunk-7haewmr7.js +0 -1
- package/dist/bin/chunk-86w3vzx8.js +0 -1
- package/dist/bin/chunk-8tfqpp9m.js +0 -1
- package/dist/bin/chunk-9tt7ahdf.js +0 -1
- package/dist/bin/chunk-9zwvysdn.js +0 -1
- package/dist/bin/chunk-a66hyvc3.js +0 -1
- package/dist/bin/chunk-b9ersj22.js +0 -1
- package/dist/bin/chunk-btrxye8p.js +0 -6
- package/dist/bin/chunk-haezjam0.js +0 -1
- package/dist/bin/chunk-hp1cqk45.js +0 -1
- package/dist/bin/chunk-mwprtzxp.js +0 -1
- package/dist/bin/chunk-nemj07g1.js +0 -1
- package/dist/bin/chunk-nfxxr6g7.js +0 -1
- package/dist/bin/chunk-q3mtvtem.js +0 -1
- package/dist/bin/chunk-qpd51n1j.js +0 -1
- package/dist/bin/chunk-rtpc6djg.js +0 -1
- package/dist/bin/chunk-s9k81gq6.js +0 -1
- package/dist/bin/chunk-wrcdcg7m.js +0 -1
- package/dist/bin/chunk-ybekawxv.js +0 -1
- package/dist/chunk-03gf4e58.js +0 -1
- package/dist/chunk-86qwnp25.js +0 -1
- package/dist/chunk-8kn7rszy.js +0 -1
- package/dist/chunk-928z0h9b.js +0 -14
- package/dist/chunk-crpbs450.js +0 -1
- package/dist/chunk-m9szynnf.js +0 -6
- package/dist/chunk-ncet7ba7.js +0 -1
- package/dist/chunk-nh7rcks9.js +0 -1
- package/dist/chunk-ypsfkgme.js +0 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import{Z,ls,Ot,xn}from"./chunk-8rkfwgb4.js";import{nr,Gr}from"./chunk-2h1q758c.js";var ml={};nr(ml,{default:()=>Dr,handler:()=>yt});var gl={};nr(gl,{default:()=>Nr,handler:()=>ft});var id={};nr(id,{EmailAnalyticsModule:()=>Je,EmailRules:()=>Ft,EmailScheduling:()=>$t,EmailSearch:()=>Mt,EmailTemplates:()=>Ce,EmailThreading:()=>Lt,SharedMailboxes:()=>Bt});var od={};nr(od,{default:()=>ps,handler:()=>ms});var sd={};nr(sd,{CallAnalytics:()=>Wt,CallRecording:()=>Gt,Callbacks:()=>it,IVRBuilder:()=>we});var ad={};nr(ad,{AbTesting:()=>me,LinkTracking:()=>Kt,MmsSupport:()=>Ht,SmsAnalytics:()=>Ut,SmsCampaigns:()=>Vt,SmsChatbot:()=>jt});var Em={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}},wm={serverless:{development:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:!0},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:1000,handlerMemory:128}},production:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:30,inactivityTimeout:60}},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST",pointInTimeRecovery:!0,connectionTTL:86400}},scaling:{maxConnections:50000,messagesPerSecond:5000,handlerMemory:256,handlerTimeout:30},monitoring:{enabled:!0,connectionThreshold:40000,errorThreshold:100,latencyThreshold:500},keepAlive:!0,keepAliveInterval:30,idleTimeout:600},notifications:{enabled:!0,mode:"serverless",channels:{public:!1,private:!0,presence:!1},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:50000,messagesPerSecond:2000,handlerMemory:128},keepAlive:!0,keepAliveInterval:60,idleTimeout:1800}},server:{development:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"ws",driver:"bun",idleTimeout:120,perMessageDeflate:!1,metrics:!1}},production:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,maxPayloadLength:16777216,backpressureLimit:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"broadcasting:"},rateLimit:{enabled:!0,max:100,window:60000,perChannel:!0,perUser:!0},loadManagement:{enabled:!0,maxConnections:1e4,maxSubscriptionsPerConnection:100,shedLoadThreshold:0.8},metrics:!0,autoScaling:{min:2,max:10,targetCPU:70}},monitoring:{enabled:!0,connectionThreshold:8000,errorThreshold:100}},highPerformance:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:60,maxPayloadLength:8388608,backpressureLimit:2097152,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!0,instances:4,redis:{enabled:!0,useElastiCache:!0,keyPrefix:"rt:"},rateLimit:{enabled:!0,max:200,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:25000,maxSubscriptionsPerConnection:50,shedLoadThreshold:0.7},metrics:{enabled:!0,path:"/metrics"},autoScaling:{min:4,max:20,targetCPU:60,targetConnections:20000}},monitoring:{enabled:!0,connectionThreshold:80000,errorThreshold:50,latencyThreshold:50}},chat:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:200,heartbeatInterval:20,inactivityTimeout:60}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:300,maxPayloadLength:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"chat:"},rateLimit:{enabled:!0,max:60,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:15000,maxSubscriptionsPerConnection:20},metrics:!0},keepAlive:!0,keepAliveInterval:25,idleTimeout:900},gaming:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:10,inactivityTimeout:30}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:30,maxPayloadLength:65536,backpressureLimit:524288,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!1,instances:4,redis:{enabled:!0,useElastiCache:!0},rateLimit:{enabled:!0,max:120,window:60000},loadManagement:{enabled:!0,maxConnections:5000,maxSubscriptionsPerConnection:10,shedLoadThreshold:0.6},metrics:!0,autoScaling:{min:4,max:16,targetCPU:50}},keepAlive:!0,keepAliveInterval:10,idleTimeout:60},single:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,sendPings:!0,perMessageDeflate:!0,instances:1,rateLimit:{enabled:!0,max:100,window:60000},loadManagement:{enabled:!0,maxConnections:1e4},metrics:!0}}}};import{isAbsolute as pt,join as Ye,relative as ur}from"node:path";var ua=".ts-cloud",ol="TS_CLOUD_STATE_DIR",gt=null;function pa(e){gt=e?.trim()||null}function ma(){return Boolean(process.env[ol]?.trim()||gt)}function wn(){return process.env[ol]?.trim()||gt||ua}function ze(...e){return Ye(wn(),...e)}function I(e,...n){let r=wn();return pt(r)?Ye(r,...n):Ye(e,r,...n)}function ga(e,n=process.cwd()){let r=(s,a)=>{let c=ur(s,a);return c===""||!c.startsWith("..")&&!pt(c)},i=pt(e)?e:Ye(n,e);return r(I(n),i)}function sl(e){let n=e.infrastructure?.compute!=null,r=Object.values(e.environments??{}).some((i)=>i?.app!=null);return{server:n,serverless:r}}function H(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:n}=sl(e);return n?"serverless":"server"}function Fr(e){let{server:n,serverless:r}=sl(e);if(n&&r)return"A project cannot be both a server and a serverless deployment. Found `infrastructure.compute` (server) AND `environments.<env>.app` (serverless Lambda). Keep one: remove `infrastructure.compute` for a serverless app, or remove `environments.<env>.app` for a server.";if(e.mode==="server"&&r&&!n)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&n&&!r)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function w(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function dr(e){return typeof e==="object"&&e!==null?e:{}}function su(e){return e===!0||typeof e==="object"&&e!==null}function mr(e,n){let r=n?e.environments?.[n]:void 0;if(r?.domain)return r.domain;let i=Object.values(e.sites??{}),s=e.sites?.main?.domain??i.find((a)=>a.domain)?.domain;if(s)return s;return`${e.project?.slug??"app"}.local`}function pr(e){let n=e.indexOf(".");return n>0?e.slice(n+1):void 0}function Y(e,n={}){let r=e.infrastructure?.compute?.managedServices?.mail,i=dr(r),s=n.environmentType??(n.environment?e.environments?.[n.environment]?.type:void 0),a=i.mode??(s==="production"?"server":"catcher"),c=a==="server",u=mr(e,n.environment),d=i.hostname??(c?`mail.${u}`:"localhost"),m=i.ports??{},p=c?{smtp:m.smtp??25,submission:m.submission??587,submissions:m.submissions??465,imap:m.imap??143,imaps:m.imaps??993,webmail:m.webmail??8080,managesieve:m.managesieve}:{smtp:m.smtp??1025,submission:m.submission,submissions:m.submissions,imap:m.imap,imaps:m.imaps,webmail:m.webmail??8025,managesieve:m.managesieve},g=i.tls??{},y=g.enabled??c,f=!!(g.systemCredentials||g.certPath&&g.keyPath);if(g.systemCredentials&&Object.values(g.systemCredentials).some((z)=>!/^\/[a-z0-9_./-]+$/i.test(z)||z.includes("/../")))throw Error("Mail system credentials require absolute certificate paths");let h=(i.accounts??[]).map((z)=>({address:z.address,password:z.password,passwordPolicy:z.passwordPolicy??"initial"})),S=typeof i.dkim==="object"&&i.dkim!==null?i.dkim:{},A=i.dkim===!1?!1:i.dkim===!0||c,R=typeof i.webmail==="object"&&i.webmail!==null?i.webmail:{},P=i.webmail===!1?!1:R.enabled??!0,C=d.includes(".")&&!d.endsWith(".local")&&!/^\d+\.\d+\.\d+\.\d+$/.test(d),E=R.domain===!1?void 0:R.domain??(c&&C?d:void 0),D=R.tls??(E?!1:y),x=[...new Set(R.aliases??[])].filter((z)=>z!==E),L=i.spam??{},B=i.delivery??(c?"direct":"none"),O=i.expose??c,F=pr(d),V=[...new Set([d,...F?[F]:[],...i.domains??[]])],ce=R.attachments?.maxFileBytes??20971520,q=R.attachments?.maxTotalBytes??20971520,J=R.attachments?.maxCount??20,K=R.undoSendSeconds??10;for(let[z,ge,Te]of[["maxFileBytes",ce,104857600],["maxTotalBytes",q,104857600],["maxCount",J,100],["undoSendSeconds",K,30]])if(!Number.isInteger(ge)||ge<0||ge>Te)throw Error(`Mail webmail ${z} must be an integer from 0 to ${Te}`);return{enabled:su(r),mode:a,version:i.version,hostname:d,domains:V,ports:p,tls:{enabled:y,acme:y&&!f&&(g.acme??!0),certPath:g.systemCredentials?"/run/credentials/mail.service/server.crt":g.certPath,keyPath:g.systemCredentials?"/run/credentials/mail.service/server.key":g.keyPath,systemCredentials:g.systemCredentials,requireForAuth:g.requireForAuth??(y&&c),acmeEmail:g.acmeEmail??h[0]?.address},dkim:{enabled:A,selector:S.selector??"default",rotate:S.rotate??!1,rotateIntervalDays:S.rotateIntervalDays??90},webmail:{enabled:P,port:R.port??p.webmail,domain:E,aliases:x,tls:D,secureCookies:R.secureCookies??(!!E||D),attachmentMaxFileBytes:ce,attachmentMaxTotalBytes:q,attachmentMaxCount:J,undoSendSeconds:K},delivery:B,sesRegion:i.sesRegion??"us-east-1",accounts:h,storagePath:i.storagePath??"/var/lib/mail",maxMessageSize:i.maxMessageSize??26214400,spam:{enabled:L.enabled??c,enforce:L.enforce??!1,junkScore:L.junkScore??5,rejectScore:L.rejectScore??12,dnsbl:L.dnsbl??c,dnsblReject:L.dnsblReject??!1,greylist:L.greylist??!1},webhookUrl:i.webhookUrl,expose:O,bindAddress:O?"0.0.0.0":"127.0.0.1"}}function jr(e){if(!e.enabled||!e.expose)return[];let n=[e.ports.smtp,e.ports.submission,e.ports.submissions,e.ports.imap,e.ports.imaps,e.ports.managesieve].filter((r)=>typeof r==="number");if(e.webmail.enabled&&!e.webmail.domain)n.push(e.webmail.port);return[...new Set(n)].sort((r,i)=>r-i)}function fa(e){if(!e.enabled)return{};let n=e.ports.submission??e.ports.smtp,r={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(n)};if(e.mode==="server"){r.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let i=e.accounts[0];if(i)r.MAIL_USERNAME=i.address,r.MAIL_PASSWORD=i.password}else r.MAIL_ENCRYPTION="null",r.MAIL_USERNAME="null",r.MAIL_PASSWORD="null";return r}function Xo(e){if(!e.enabled||!e.webmail.enabled||!e.webmail.domain)return{};let n=[e.webmail.domain,...e.webmail.aliases];if(!Number.isInteger(e.webmail.port)||e.webmail.port<1||e.webmail.port>65535)throw Error("Mail webmail port must be between 1 and 65535");return Object.fromEntries(n.map((r,i)=>{if(!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(r))throw Error(`Invalid mail webmail hostname: ${r}`);return[`__mail_webmail_${i}`,{domain:r,proxyTo:`localhost:${e.webmail.port}`}]}))}function de(e,n={}){let r=e.infrastructure?.compute?.proxy,i=Y(e,n);if(!i.enabled||!i.webmail.enabled||!i.webmail.domain)return r;return{engine:"rpx",onDemandTls:!0,onDemandTlsEmail:i.tls.acmeEmail??`webmaster@${i.webmail.domain}`,...r}}function U(e){if(e.cloud?.provider)return e.cloud.provider;if(e.ssh?.hosts?.length)return"ssh";if(e.hetzner?.apiToken)return"hetzner";return"aws"}class Qo{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,n){return this.template.Resources[e]=n,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,n){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=n,this}addOutput(e,n){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=n,this}addMetadata(e,n){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[e]=n,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,n=0){let r=" ".repeat(n),i="";for(let[s,a]of Object.entries(e)){if(a===null||a===void 0)continue;if(typeof a==="object"&&!Array.isArray(a))i+=`${r}${s}:
|
|
1
|
+
import{ee,ys,Lt,On}from"./chunk-8ctmc30y.js";import{createRequire as wr}from"node:module";var Rr=Object.defineProperty;var Pr=(e)=>e;function Er(e,n){this[e]=Pr.bind(null,n)}var jr=(e,n)=>{for(var r in n)Rr(e,r,{get:n[r],enumerable:!0,configurable:!0,set:Er.bind(n,r)})};var ml=wr(import.meta.url);var Tl={};jr(Tl,{default:()=>Xr,handler:()=>bt});var El={};jr(El,{default:()=>ei,handler:()=>St});var gd={};jr(gd,{EmailAnalyticsModule:()=>Ze,EmailRules:()=>jt,EmailScheduling:()=>Ut,EmailSearch:()=>Wt,EmailTemplates:()=>Ae,EmailThreading:()=>Vt,SharedMailboxes:()=>Ht});var fd={};jr(fd,{default:()=>zs,handler:()=>qs});var hd={};jr(hd,{CallAnalytics:()=>qt,CallRecording:()=>Kt,Callbacks:()=>ot,IVRBuilder:()=>we});var yd={};jr(yd,{AbTesting:()=>pe,LinkTracking:()=>Xt,MmsSupport:()=>Jt,SmsAnalytics:()=>Qt,SmsCampaigns:()=>zt,SmsChatbot:()=>Yt});var $m={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}},Lm={serverless:{development:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:!0},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:1000,handlerMemory:128}},production:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:30,inactivityTimeout:60}},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST",pointInTimeRecovery:!0,connectionTTL:86400}},scaling:{maxConnections:50000,messagesPerSecond:5000,handlerMemory:256,handlerTimeout:30},monitoring:{enabled:!0,connectionThreshold:40000,errorThreshold:100,latencyThreshold:500},keepAlive:!0,keepAliveInterval:30,idleTimeout:600},notifications:{enabled:!0,mode:"serverless",channels:{public:!1,private:!0,presence:!1},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:50000,messagesPerSecond:2000,handlerMemory:128},keepAlive:!0,keepAliveInterval:60,idleTimeout:1800}},server:{development:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"ws",driver:"bun",idleTimeout:120,perMessageDeflate:!1,metrics:!1}},production:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,maxPayloadLength:16777216,backpressureLimit:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"broadcasting:"},rateLimit:{enabled:!0,max:100,window:60000,perChannel:!0,perUser:!0},loadManagement:{enabled:!0,maxConnections:1e4,maxSubscriptionsPerConnection:100,shedLoadThreshold:0.8},metrics:!0,autoScaling:{min:2,max:10,targetCPU:70}},monitoring:{enabled:!0,connectionThreshold:8000,errorThreshold:100}},highPerformance:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:60,maxPayloadLength:8388608,backpressureLimit:2097152,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!0,instances:4,redis:{enabled:!0,useElastiCache:!0,keyPrefix:"rt:"},rateLimit:{enabled:!0,max:200,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:25000,maxSubscriptionsPerConnection:50,shedLoadThreshold:0.7},metrics:{enabled:!0,path:"/metrics"},autoScaling:{min:4,max:20,targetCPU:60,targetConnections:20000}},monitoring:{enabled:!0,connectionThreshold:80000,errorThreshold:50,latencyThreshold:50}},chat:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:200,heartbeatInterval:20,inactivityTimeout:60}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:300,maxPayloadLength:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"chat:"},rateLimit:{enabled:!0,max:60,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:15000,maxSubscriptionsPerConnection:20},metrics:!0},keepAlive:!0,keepAliveInterval:25,idleTimeout:900},gaming:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:10,inactivityTimeout:30}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:30,maxPayloadLength:65536,backpressureLimit:524288,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!1,instances:4,redis:{enabled:!0,useElastiCache:!0},rateLimit:{enabled:!0,max:120,window:60000},loadManagement:{enabled:!0,maxConnections:5000,maxSubscriptionsPerConnection:10,shedLoadThreshold:0.6},metrics:!0,autoScaling:{min:4,max:16,targetCPU:50}},keepAlive:!0,keepAliveInterval:10,idleTimeout:60},single:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,sendPings:!0,perMessageDeflate:!0,instances:1,rateLimit:{enabled:!0,max:100,window:60000},loadManagement:{enabled:!0,maxConnections:1e4},metrics:!0}}}};import{isAbsolute as ft,join as Xe,relative as Ir}from"node:path";var Sa=".ts-cloud",gl="TS_CLOUD_STATE_DIR",ht=null;function va(e){ht=e?.trim()||null}function Ca(){return Boolean(process.env[gl]?.trim()||ht)}function An(){return process.env[gl]?.trim()||ht||Sa}function He(...e){return Xe(An(),...e)}function I(e,...n){let r=An();return ft(r)?Xe(r,...n):Xe(e,r,...n)}function Ta(e,n=process.cwd()){let r=(s,a)=>{let c=Ir(s,a);return c===""||!c.startsWith("..")&&!ft(c)},i=ft(e)?e:Xe(n,e);return r(I(n),i)}function fl(e){let n=e.infrastructure?.compute!=null,r=Object.values(e.environments??{}).some((i)=>i?.app!=null);return{server:n,serverless:r}}function H(e){if(e.mode==="server"||e.mode==="serverless")return e.mode;let{serverless:n}=fl(e);return n?"serverless":"server"}function Vr(e){let{server:n,serverless:r}=fl(e);if(n&&r)return"A project cannot be both a server and a serverless deployment. Found `infrastructure.compute` (server) AND `environments.<env>.app` (serverless Lambda). Keep one: remove `infrastructure.compute` for a serverless app, or remove `environments.<env>.app` for a server.";if(e.mode==="server"&&r&&!n)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(e.mode==="serverless"&&n&&!r)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function w(e){return e.infrastructure?.appDatabase??e.infrastructure?.compute?.database}function Dr(e){return typeof e==="object"&&e!==null?e:{}}function hu(e){return e===!0||typeof e==="object"&&e!==null}function Nr(e,n){let r=n?e.environments?.[n]:void 0;if(r?.domain)return r.domain;let i=Object.values(e.sites??{}),s=e.sites?.main?.domain??i.find((a)=>a.domain)?.domain;if(s)return s;return`${e.project?.slug??"app"}.local`}function xr(e){let n=e.indexOf(".");return n>0?e.slice(n+1):void 0}function Y(e,n={}){let r=e.infrastructure?.compute?.managedServices?.mail,i=Dr(r),s=n.environmentType??(n.environment?e.environments?.[n.environment]?.type:void 0),a=i.mode??(s==="production"?"server":"catcher"),c=a==="server",u=Nr(e,n.environment),d=i.hostname??(c?`mail.${u}`:"localhost"),m=i.ports??{},p=c?{smtp:m.smtp??25,submission:m.submission??587,submissions:m.submissions??465,imap:m.imap??143,imaps:m.imaps??993,webmail:m.webmail??8080,managesieve:m.managesieve}:{smtp:m.smtp??1025,submission:m.submission,submissions:m.submissions,imap:m.imap,imaps:m.imaps,webmail:m.webmail??8025,managesieve:m.managesieve},g=i.tls??{},y=g.enabled??c,f=!!(g.systemCredentials||g.certPath&&g.keyPath);if(g.systemCredentials&&Object.values(g.systemCredentials).some((z)=>!/^\/[a-z0-9_./-]+$/i.test(z)||z.includes("/../")))throw Error("Mail system credentials require absolute certificate paths");let h=(i.accounts??[]).map((z)=>({address:z.address,password:z.password,passwordPolicy:z.passwordPolicy??"initial"})),S=typeof i.dkim==="object"&&i.dkim!==null?i.dkim:{},A=i.dkim===!1?!1:i.dkim===!0||c,R=typeof i.webmail==="object"&&i.webmail!==null?i.webmail:{},P=i.webmail===!1?!1:R.enabled??!0,C=d.includes(".")&&!d.endsWith(".local")&&!/^\d+\.\d+\.\d+\.\d+$/.test(d),E=R.domain===!1?void 0:R.domain??(c&&C?d:void 0),D=R.tls??(E?!1:y),x=[...new Set(R.aliases??[])].filter((z)=>z!==E),L=i.spam??{},B=i.delivery??(c?"direct":"none"),O=i.expose??c,F=xr(d),V=[...new Set([d,...F?[F]:[],...i.domains??[]])],le=R.attachments?.maxFileBytes??20971520,q=R.attachments?.maxTotalBytes??20971520,J=R.attachments?.maxCount??20,K=R.undoSendSeconds??10;for(let[z,ye,Te]of[["maxFileBytes",le,104857600],["maxTotalBytes",q,104857600],["maxCount",J,100],["undoSendSeconds",K,30]])if(!Number.isInteger(ye)||ye<0||ye>Te)throw Error(`Mail webmail ${z} must be an integer from 0 to ${Te}`);return{enabled:hu(r),mode:a,version:i.version,hostname:d,domains:V,ports:p,tls:{enabled:y,acme:y&&!f&&(g.acme??!0),certPath:g.systemCredentials?"/run/credentials/mail.service/server.crt":g.certPath,keyPath:g.systemCredentials?"/run/credentials/mail.service/server.key":g.keyPath,systemCredentials:g.systemCredentials,requireForAuth:g.requireForAuth??(y&&c),acmeEmail:g.acmeEmail??h[0]?.address},dkim:{enabled:A,selector:S.selector??"default",rotate:S.rotate??!1,rotateIntervalDays:S.rotateIntervalDays??90},webmail:{enabled:P,port:R.port??p.webmail,domain:E,aliases:x,tls:D,secureCookies:R.secureCookies??(!!E||D),attachmentMaxFileBytes:le,attachmentMaxTotalBytes:q,attachmentMaxCount:J,undoSendSeconds:K},delivery:B,sesRegion:i.sesRegion??"us-east-1",accounts:h,storagePath:i.storagePath??"/var/lib/mail",maxMessageSize:i.maxMessageSize??26214400,spam:{enabled:L.enabled??c,enforce:L.enforce??!1,junkScore:L.junkScore??5,rejectScore:L.rejectScore??12,dnsbl:L.dnsbl??c,dnsblReject:L.dnsblReject??!1,greylist:L.greylist??!1},webhookUrl:i.webhookUrl,expose:O,bindAddress:O?"0.0.0.0":"127.0.0.1"}}function zr(e){if(!e.enabled||!e.expose)return[];let n=[e.ports.smtp,e.ports.submission,e.ports.submissions,e.ports.imap,e.ports.imaps,e.ports.managesieve].filter((r)=>typeof r==="number");if(e.webmail.enabled&&!e.webmail.domain)n.push(e.webmail.port);return[...new Set(n)].sort((r,i)=>r-i)}function Ea(e){if(!e.enabled)return{};let n=e.ports.submission??e.ports.smtp,r={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(n)};if(e.mode==="server"){r.MAIL_ENCRYPTION=e.tls.enabled?"tls":"null";let i=e.accounts[0];if(i)r.MAIL_USERNAME=i.address,r.MAIL_PASSWORD=i.password}else r.MAIL_ENCRYPTION="null",r.MAIL_USERNAME="null",r.MAIL_PASSWORD="null";return r}function ts(e){if(!e.enabled||!e.webmail.enabled||!e.webmail.domain)return{};let n=[e.webmail.domain,...e.webmail.aliases];if(!Number.isInteger(e.webmail.port)||e.webmail.port<1||e.webmail.port>65535)throw Error("Mail webmail port must be between 1 and 65535");return Object.fromEntries(n.map((r,i)=>{if(!/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(r))throw Error(`Invalid mail webmail hostname: ${r}`);return[`__mail_webmail_${i}`,{domain:r,proxyTo:`localhost:${e.webmail.port}`}]}))}function ue(e,n={}){let r=e.infrastructure?.compute?.proxy,i=Y(e,n);if(!i.enabled||!i.webmail.enabled||!i.webmail.domain)return r;return{engine:"rpx",onDemandTls:!0,onDemandTlsEmail:i.tls.acmeEmail??`webmaster@${i.webmail.domain}`,...r}}function U(e){if(e.cloud?.provider)return e.cloud.provider;if(e.ssh?.hosts?.length)return"ssh";if(e.hetzner?.apiToken)return"hetzner";return"aws"}class rs{template;constructor(e){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:e,Resources:{}}}addResource(e,n){return this.template.Resources[e]=n,this}addResources(e){return Object.assign(this.template.Resources,e),this}addParameter(e,n){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[e]=n,this}addOutput(e,n){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[e]=n,this}addMetadata(e,n){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[e]=n,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,n=0){let r=" ".repeat(n),i="";for(let[s,a]of Object.entries(e)){if(a===null||a===void 0)continue;if(typeof a==="object"&&!Array.isArray(a))i+=`${r}${s}:
|
|
2
2
|
${this.convertToYAML(a,n+1)}`;else if(Array.isArray(a)){i+=`${r}${s}:
|
|
3
3
|
`;for(let c of a)if(typeof c==="object")i+=`${r} -
|
|
4
4
|
${this.convertToYAML(c,n+2)}`;else i+=`${r} - ${c}
|
|
5
5
|
`}else i+=`${r}${s}: ${a}
|
|
6
|
-
`}return i}}function au(e){let n=[],r=[],i=[];if(gr(e,n),e.Resources)yr(e.Resources,n,r);else n.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});if(e.Parameters)fr(e.Parameters,n,r);if(e.Outputs)hr(e.Outputs,n);br(e,n);let s=Sr(e);if(s.length>0)for(let a of s)n.push({path:"Resources",message:`Circular dependency detected: ${a.join(" → ")}`,severity:"error"});return Cr(e,r,i),{valid:n.length===0,errors:n,warnings:r,info:i}}function gr(e,n){if(!e.AWSTemplateFormatVersion)n.push({path:"AWSTemplateFormatVersion",message:"Template should specify AWSTemplateFormatVersion",severity:"error"});else if(e.AWSTemplateFormatVersion!=="2010-09-09")n.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion must be "2010-09-09"',severity:"error"})}function yr(e,n,r){let i=Object.keys(e);if(i.length===0){n.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});return}if(i.length>500)r.push({path:"Resources",message:`Template contains ${i.length} resources (limit is 500)`,severity:"warning"});for(let s of i){let a=e[s];if(!/^[a-zA-Z0-9]+$/.test(s))n.push({path:`Resources.${s}`,message:"Logical ID must contain only alphanumeric characters",severity:"error"});if(!a.Type)n.push({path:`Resources.${s}.Type`,message:"Resource Type is required",severity:"error"});else if(!a.Type.startsWith("AWS::")&&!a.Type.startsWith("Custom::"))n.push({path:`Resources.${s}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(a.DeletionPolicy&&!["Delete","Retain","Snapshot"].includes(a.DeletionPolicy))n.push({path:`Resources.${s}.DeletionPolicy`,message:'DeletionPolicy must be "Delete", "Retain", or "Snapshot"',severity:"error"});if(!a.DeletionPolicy&&en(a.Type))r.push({path:`Resources.${s}.DeletionPolicy`,message:`${a.Type} should specify DeletionPolicy to prevent accidental data loss`,severity:"warning"})}}function fr(e,n,r){let i=Object.keys(e);if(i.length>200)r.push({path:"Parameters",message:`Template contains ${i.length} parameters (limit is 200)`,severity:"warning"});for(let s of i){let a=e[s];if(!a.Type)n.push({path:`Parameters.${s}.Type`,message:"Parameter Type is required",severity:"error"});let c=["String","Number","List<Number>","CommaDelimitedList","AWS::EC2::AvailabilityZone::Name","AWS::EC2::Image::Id","AWS::EC2::Instance::Id","AWS::EC2::KeyPair::KeyName","AWS::EC2::SecurityGroup::GroupName","AWS::EC2::SecurityGroup::Id","AWS::EC2::Subnet::Id","AWS::EC2::Volume::Id","AWS::EC2::VPC::Id","AWS::Route53::HostedZone::Id","List<AWS::EC2::AvailabilityZone::Name>","List<AWS::EC2::Image::Id>","List<AWS::EC2::Instance::Id>","List<AWS::EC2::SecurityGroup::GroupName>","List<AWS::EC2::SecurityGroup::Id>","List<AWS::EC2::Subnet::Id>","List<AWS::EC2::Volume::Id>","List<AWS::EC2::VPC::Id>","List<AWS::Route53::HostedZone::Id>","AWS::SSM::Parameter::Name","AWS::SSM::Parameter::Value<String>","AWS::SSM::Parameter::Value<List<String>>","AWS::SSM::Parameter::Value<CommaDelimitedList>"];if(a.Type&&!c.includes(a.Type))n.push({path:`Parameters.${s}.Type`,message:`Invalid parameter type: ${a.Type}`,severity:"error"})}}function hr(e,n){let r=Object.keys(e);for(let i of r)if(!e[i].Value)n.push({path:`Outputs.${i}.Value`,message:"Output Value is required",severity:"error"})}function br(e,n){let r=e.Resources||{},i=e.Parameters||{},s=new Set(Object.keys(r)),a=new Set(Object.keys(i));function c(u,d){if(typeof u!=="object"||u===null)return;if(u.Ref){let m=u.Ref;if(!s.has(m)&&!a.has(m)&&m!=="AWS::Region"&&m!=="AWS::AccountId"&&m!=="AWS::StackName"&&m!=="AWS::StackId"&&m!=="AWS::URLSuffix"&&m!=="AWS::Partition"&&m!=="AWS::NoValue")n.push({path:d,message:`Reference to non-existent resource or parameter: ${m}`,severity:"error"})}if(u["Fn::GetAtt"]){let m=u["Fn::GetAtt"];if(Array.isArray(m)&&m.length>=1){let p=m[0];if(!s.has(p))n.push({path:d,message:`GetAtt references non-existent resource: ${p}`,severity:"error"})}}for(let m in u)c(u[m],`${d}.${m}`)}for(let u in r)c(r[u],`Resources.${u}`);if(e.Outputs)for(let u in e.Outputs)c(e.Outputs[u],`Outputs.${u}`)}function Sr(e){let n=e.Resources||{},r=new Map;for(let u in n){let d=new Set,m=n[u];if(m.DependsOn)if(Array.isArray(m.DependsOn))m.DependsOn.forEach((g)=>d.add(g));else d.add(m.DependsOn);Ar(m).forEach((g)=>d.add(g)),r.set(u,d)}let i=[],s=new Set,a=new Set;function c(u,d){s.add(u),a.add(u),d.push(u);let m=r.get(u)||new Set;for(let p of m)if(!s.has(p))c(p,[...d]);else if(a.has(p)){let g=d.indexOf(p),y=[...d.slice(g),p];i.push(y)}a.delete(u)}for(let u of r.keys())if(!s.has(u))c(u,[]);return i}function Ar(e){let n=new Set;function r(i){if(typeof i!=="object"||i===null)return;if(i.Ref&&typeof i.Ref==="string"){if(!i.Ref.startsWith("AWS::"))n.add(i.Ref)}if(i["Fn::GetAtt"]&&Array.isArray(i["Fn::GetAtt"]))n.add(i["Fn::GetAtt"][0]);for(let s in i)r(i[s])}return r(e),n}function en(e){return["AWS::S3::Bucket","AWS::DynamoDB::Table","AWS::RDS::DBInstance","AWS::RDS::DBCluster","AWS::ElastiCache::CacheCluster","AWS::ElastiCache::ReplicationGroup","AWS::EFS::FileSystem","AWS::OpenSearchService::Domain"].includes(e)}function Cr(e,n,r){let i=e.Resources||{};if(!e.Description)r.push({path:"Description",message:"Consider adding a Description to the template",severity:"info"});for(let s in i){let a=i[s],c=a.Properties;if(c&&!c.Tags&&vr(a.Type))r.push({path:`Resources.${s}`,message:`Consider adding Tags to ${a.Type}`,severity:"info"});if(en(a.Type)){if(a.Type==="AWS::S3::Bucket"&&!c?.BucketEncryption)n.push({path:`Resources.${s}`,message:"S3 bucket should enable encryption",severity:"warning"});if(a.Type==="AWS::RDS::DBInstance"&&!c?.StorageEncrypted)n.push({path:`Resources.${s}`,message:"RDS instance should enable storage encryption",severity:"warning"})}}}function vr(e){return!["AWS::CloudFormation::Stack","AWS::CloudFormation::WaitCondition","AWS::CloudFormation::WaitConditionHandle"].includes(e)}function cu(e){let n=[],r=[],i=[],s=Buffer.byteLength(e,"utf8"),a=s/1024,c=51200,u=460800;if(s>460800)n.push({path:"Template",message:`Template size (${a.toFixed(2)} KB) exceeds maximum size of 450 KB`,severity:"error"});else if(s>51200)r.push({path:"Template",message:`Template size (${a.toFixed(2)} KB) exceeds 50 KB. Must use S3 for deployment.`,severity:"warning"});return{valid:n.length===0,errors:n,warnings:r,info:i}}function lu(e){let n=[],r=[],i=[],s=e.Resources||{},a=e.Parameters||{},c=e.Outputs||{};if(Object.keys(s).length>500)n.push({path:"Resources",message:`Template has ${Object.keys(s).length} resources (limit is 500)`,severity:"error"});if(Object.keys(a).length>200)n.push({path:"Parameters",message:`Template has ${Object.keys(a).length} parameters (limit is 200)`,severity:"error"});if(Object.keys(c).length>200)n.push({path:"Outputs",message:`Template has ${Object.keys(c).length} outputs (limit is 200)`,severity:"error"});return{valid:n.length===0,errors:n,warnings:r,info:i}}var v={Ref:(e)=>({Ref:e}),GetAtt:(e,n)=>({"Fn::GetAtt":[e,n]}),Sub:(e,n)=>{if(n)return{"Fn::Sub":[e,n]};return{"Fn::Sub":e}},Join:(e,n)=>({"Fn::Join":[e,n]}),Select:(e,n)=>({"Fn::Select":[e,n]}),Split:(e,n)=>({"Fn::Split":[e,n]}),GetAZs:(e="")=>({"Fn::GetAZs":e}),ImportValue:(e)=>({"Fn::ImportValue":e}),If:(e,n,r)=>({"Fn::If":[e,n,r]}),Equals:(e,n)=>({"Fn::Equals":[e,n]}),And:(...e)=>({"Fn::And":e}),Or:(...e)=>({"Fn::Or":e}),Not:(e)=>({"Fn::Not":[e]}),Base64:(e)=>({"Fn::Base64":e})},du={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 l(e){let{slug:n,environment:r,resourceType:i,timestamp:s,suffix:a}=e,c=[n,r,i];if(s)c.push(s);if(a)c.push(a);return c.join("-")}function o(e){return e.split("-").map((n)=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}function Am(){return Date.now().toString()}function Rm(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function T(e,n){return e.project.stackName??`${e.project.slug}-${n}`}function ha(e,n,r,i){return r.stackName??`${e.project.slug}-${i}-${n}-site`}function ya(e,n){return`${e.project.slug}-${n}`}function ba(e,n,r,i){if(i)return i;if(r==="main")return`${e}-${n}-site`;return`${e}-${n}-${r}`}function Im(e,n,r,i){return i??`${e}-${n}-${r}`}function Pm(e,n){return`${e}-${n}-deploy`}function $e(e,n){return`${e.project.slug}-${n}-app`}function Sa(e,n){return`${e}-${n}-deployments`}function Fi(e,n){return`${e}-${n}-assets`}class uu{nodes=new Map;addResource(e,n){let r=this.extractDependencies(n);this.nodes.set(e,{logicalId:e,resource:n,dependencies:r})}extractDependencies(e){let n=new Set;if(e.DependsOn)if(Array.isArray(e.DependsOn))e.DependsOn.forEach((r)=>n.add(r));else n.add(e.DependsOn);return this.findReferences(e.Properties||{},n),n}findReferences(e,n){if(!e||typeof e!=="object")return;if("Ref"in e&&typeof e.Ref==="string"){if(!e.Ref.startsWith("AWS::"))n.add(e.Ref)}if("Fn::GetAtt"in e&&Array.isArray(e["Fn::GetAtt"]))n.add(e["Fn::GetAtt"][0]);for(let r of Object.values(e))if(typeof r==="object")this.findReferences(r,n)}topologicalSort(){let e=[],n=new Set,r=new Set,i=(s)=>{if(n.has(s))return;if(r.has(s))throw Error(`Circular dependency detected: ${s}`);r.add(s);let a=this.nodes.get(s);if(a)for(let c of a.dependencies)i(c);r.delete(s),n.add(s),e.push(s)};for(let s of this.nodes.keys())i(s);return e}validate(){for(let[e,n]of this.nodes.entries())for(let r of n.dependencies)if(!this.nodes.has(r))throw Error(`Resource "${e}" depends on "${r}" which does not exist`)}getDependents(e){let n=[];for(let[r,i]of this.nodes.entries())if(i.dependencies.has(e))n.push(r);return n}}function Dm(e,n){let r=[],i=[],s=[],a=[],c=[],u=e.Resources||{},d=n.Resources||{},m=new Set([...Object.keys(u),...Object.keys(d)]);for(let g of m){let y=u[g],f=d[g];if(!y&&f)r.push({logicalId:g,action:"add",resourceType:f.Type});else if(y&&!f)i.push({logicalId:g,action:"remove",resourceType:y.Type});else if(y&&f)if(y.Type!==f.Type)a.push({logicalId:g,action:"replace",resourceType:f.Type,reason:`Type changed from ${y.Type} to ${f.Type}`});else{let h=tn(y.Properties||{},f.Properties||{});if(h.length>0)if(Tr(y.Type,h))a.push({logicalId:g,action:"replace",resourceType:f.Type,changes:h,reason:"Property changes require replacement"});else s.push({logicalId:g,action:"update",resourceType:f.Type,changes:h});else c.push(g)}}let p=Rr([...i,...a,...s]);return{added:r,removed:i,updated:s,replaced:a,unchanged:c,summary:{totalChanges:r.length+i.length+s.length+a.length,requiresReplacement:a.length>0,dangerousChanges:p}}}function tn(e,n,r=""){let i=[],s=new Set([...Object.keys(e),...Object.keys(n)]);for(let a of s){let c=r?`${r}.${a}`:a,u=e[a],d=n[a];if(u===void 0&&d!==void 0)i.push({path:c,oldValue:void 0,newValue:d});else if(u!==void 0&&d===void 0)i.push({path:c,oldValue:u,newValue:void 0});else if(typeof u!==typeof d)i.push({path:c,oldValue:u,newValue:d});else if(typeof u==="object"&&u!==null)if(Array.isArray(u)&&Array.isArray(d)){if(JSON.stringify(u)!==JSON.stringify(d))i.push({path:c,oldValue:u,newValue:d})}else if(!Array.isArray(u)&&!Array.isArray(d)){let m=tn(u,d,c);i.push(...m)}else i.push({path:c,oldValue:u,newValue:d});else if(u!==d)i.push({path:c,oldValue:u,newValue:d})}return i}function Tr(e,n){let i={"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(!i)return!1;for(let s of n){let a=s.path.split(".")[0];if(i.has(a))return!0}return!1}function Rr(e){let n=[];for(let r of e){if(r.action==="remove"&&(r.resourceType==="AWS::RDS::DBInstance"||r.resourceType==="AWS::DynamoDB::Table"||r.resourceType==="AWS::ElastiCache::CacheCluster"))n.push(`Removing ${r.resourceType} ${r.logicalId} - data loss risk!`);if(r.action==="replace"&&(r.resourceType==="AWS::RDS::DBInstance"||r.resourceType==="AWS::DynamoDB::Table"))n.push(`Replacing ${r.resourceType} ${r.logicalId} - data loss risk!`);if((r.action==="remove"||r.action==="replace")&&r.resourceType==="AWS::S3::Bucket")n.push(`${r.action==="remove"?"Removing":"Replacing"} S3 bucket ${r.logicalId} - data loss risk!`);if(r.action==="replace"&&r.resourceType==="AWS::EC2::Instance")n.push(`Replacing EC2 instance ${r.logicalId} - downtime expected`);if(r.action==="update"&&r.resourceType==="AWS::EC2::SecurityGroup")n.push(`Updating security group ${r.logicalId} - may affect connectivity`);if((r.action==="update"||r.action==="replace")&&(r.resourceType==="AWS::IAM::Role"||r.resourceType==="AWS::IAM::Policy"))n.push(`Modifying IAM ${r.resourceType.split("::")[2]} ${r.logicalId} - may affect permissions`)}return n}function km(e){let n=[];if(n.push(`=== Stack Update Analysis ===
|
|
6
|
+
`}return i}}function yu(e){let n=[],r=[],i=[];if(kr(e,n),e.Resources)Mr(e.Resources,n,r);else n.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});if(e.Parameters)Lr(e.Parameters,n,r);if(e.Outputs)Or(e.Outputs,n);$r(e,n);let s=Br(e);if(s.length>0)for(let a of s)n.push({path:"Resources",message:`Circular dependency detected: ${a.join(" → ")}`,severity:"error"});return _r(e,r,i),{valid:n.length===0,errors:n,warnings:r,info:i}}function kr(e,n){if(!e.AWSTemplateFormatVersion)n.push({path:"AWSTemplateFormatVersion",message:"Template should specify AWSTemplateFormatVersion",severity:"error"});else if(e.AWSTemplateFormatVersion!=="2010-09-09")n.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion must be "2010-09-09"',severity:"error"})}function Mr(e,n,r){let i=Object.keys(e);if(i.length===0){n.push({path:"Resources",message:"Template must contain at least one resource",severity:"error"});return}if(i.length>500)r.push({path:"Resources",message:`Template contains ${i.length} resources (limit is 500)`,severity:"warning"});for(let s of i){let a=e[s];if(!/^[a-zA-Z0-9]+$/.test(s))n.push({path:`Resources.${s}`,message:"Logical ID must contain only alphanumeric characters",severity:"error"});if(!a.Type)n.push({path:`Resources.${s}.Type`,message:"Resource Type is required",severity:"error"});else if(!a.Type.startsWith("AWS::")&&!a.Type.startsWith("Custom::"))n.push({path:`Resources.${s}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(a.DeletionPolicy&&!["Delete","Retain","Snapshot"].includes(a.DeletionPolicy))n.push({path:`Resources.${s}.DeletionPolicy`,message:'DeletionPolicy must be "Delete", "Retain", or "Snapshot"',severity:"error"});if(!a.DeletionPolicy&&sn(a.Type))r.push({path:`Resources.${s}.DeletionPolicy`,message:`${a.Type} should specify DeletionPolicy to prevent accidental data loss`,severity:"warning"})}}function Lr(e,n,r){let i=Object.keys(e);if(i.length>200)r.push({path:"Parameters",message:`Template contains ${i.length} parameters (limit is 200)`,severity:"warning"});for(let s of i){let a=e[s];if(!a.Type)n.push({path:`Parameters.${s}.Type`,message:"Parameter Type is required",severity:"error"});let c=["String","Number","List<Number>","CommaDelimitedList","AWS::EC2::AvailabilityZone::Name","AWS::EC2::Image::Id","AWS::EC2::Instance::Id","AWS::EC2::KeyPair::KeyName","AWS::EC2::SecurityGroup::GroupName","AWS::EC2::SecurityGroup::Id","AWS::EC2::Subnet::Id","AWS::EC2::Volume::Id","AWS::EC2::VPC::Id","AWS::Route53::HostedZone::Id","List<AWS::EC2::AvailabilityZone::Name>","List<AWS::EC2::Image::Id>","List<AWS::EC2::Instance::Id>","List<AWS::EC2::SecurityGroup::GroupName>","List<AWS::EC2::SecurityGroup::Id>","List<AWS::EC2::Subnet::Id>","List<AWS::EC2::Volume::Id>","List<AWS::EC2::VPC::Id>","List<AWS::Route53::HostedZone::Id>","AWS::SSM::Parameter::Name","AWS::SSM::Parameter::Value<String>","AWS::SSM::Parameter::Value<List<String>>","AWS::SSM::Parameter::Value<CommaDelimitedList>"];if(a.Type&&!c.includes(a.Type))n.push({path:`Parameters.${s}.Type`,message:`Invalid parameter type: ${a.Type}`,severity:"error"})}}function Or(e,n){let r=Object.keys(e);for(let i of r)if(!e[i].Value)n.push({path:`Outputs.${i}.Value`,message:"Output Value is required",severity:"error"})}function $r(e,n){let r=e.Resources||{},i=e.Parameters||{},s=new Set(Object.keys(r)),a=new Set(Object.keys(i));function c(u,d){if(typeof u!=="object"||u===null)return;if(u.Ref){let m=u.Ref;if(!s.has(m)&&!a.has(m)&&m!=="AWS::Region"&&m!=="AWS::AccountId"&&m!=="AWS::StackName"&&m!=="AWS::StackId"&&m!=="AWS::URLSuffix"&&m!=="AWS::Partition"&&m!=="AWS::NoValue")n.push({path:d,message:`Reference to non-existent resource or parameter: ${m}`,severity:"error"})}if(u["Fn::GetAtt"]){let m=u["Fn::GetAtt"];if(Array.isArray(m)&&m.length>=1){let p=m[0];if(!s.has(p))n.push({path:d,message:`GetAtt references non-existent resource: ${p}`,severity:"error"})}}for(let m in u)c(u[m],`${d}.${m}`)}for(let u in r)c(r[u],`Resources.${u}`);if(e.Outputs)for(let u in e.Outputs)c(e.Outputs[u],`Outputs.${u}`)}function Br(e){let n=e.Resources||{},r=new Map;for(let u in n){let d=new Set,m=n[u];if(m.DependsOn)if(Array.isArray(m.DependsOn))m.DependsOn.forEach((g)=>d.add(g));else d.add(m.DependsOn);Fr(m).forEach((g)=>d.add(g)),r.set(u,d)}let i=[],s=new Set,a=new Set;function c(u,d){s.add(u),a.add(u),d.push(u);let m=r.get(u)||new Set;for(let p of m)if(!s.has(p))c(p,[...d]);else if(a.has(p)){let g=d.indexOf(p),y=[...d.slice(g),p];i.push(y)}a.delete(u)}for(let u of r.keys())if(!s.has(u))c(u,[]);return i}function Fr(e){let n=new Set;function r(i){if(typeof i!=="object"||i===null)return;if(i.Ref&&typeof i.Ref==="string"){if(!i.Ref.startsWith("AWS::"))n.add(i.Ref)}if(i["Fn::GetAtt"]&&Array.isArray(i["Fn::GetAtt"]))n.add(i["Fn::GetAtt"][0]);for(let s in i)r(i[s])}return r(e),n}function sn(e){return["AWS::S3::Bucket","AWS::DynamoDB::Table","AWS::RDS::DBInstance","AWS::RDS::DBCluster","AWS::ElastiCache::CacheCluster","AWS::ElastiCache::ReplicationGroup","AWS::EFS::FileSystem","AWS::OpenSearchService::Domain"].includes(e)}function _r(e,n,r){let i=e.Resources||{};if(!e.Description)r.push({path:"Description",message:"Consider adding a Description to the template",severity:"info"});for(let s in i){let a=i[s],c=a.Properties;if(c&&!c.Tags&&Wr(a.Type))r.push({path:`Resources.${s}`,message:`Consider adding Tags to ${a.Type}`,severity:"info"});if(sn(a.Type)){if(a.Type==="AWS::S3::Bucket"&&!c?.BucketEncryption)n.push({path:`Resources.${s}`,message:"S3 bucket should enable encryption",severity:"warning"});if(a.Type==="AWS::RDS::DBInstance"&&!c?.StorageEncrypted)n.push({path:`Resources.${s}`,message:"RDS instance should enable storage encryption",severity:"warning"})}}}function Wr(e){return!["AWS::CloudFormation::Stack","AWS::CloudFormation::WaitCondition","AWS::CloudFormation::WaitConditionHandle"].includes(e)}function bu(e){let n=[],r=[],i=[],s=Buffer.byteLength(e,"utf8"),a=s/1024,c=51200,u=460800;if(s>460800)n.push({path:"Template",message:`Template size (${a.toFixed(2)} KB) exceeds maximum size of 450 KB`,severity:"error"});else if(s>51200)r.push({path:"Template",message:`Template size (${a.toFixed(2)} KB) exceeds 50 KB. Must use S3 for deployment.`,severity:"warning"});return{valid:n.length===0,errors:n,warnings:r,info:i}}function Su(e){let n=[],r=[],i=[],s=e.Resources||{},a=e.Parameters||{},c=e.Outputs||{};if(Object.keys(s).length>500)n.push({path:"Resources",message:`Template has ${Object.keys(s).length} resources (limit is 500)`,severity:"error"});if(Object.keys(a).length>200)n.push({path:"Parameters",message:`Template has ${Object.keys(a).length} parameters (limit is 200)`,severity:"error"});if(Object.keys(c).length>200)n.push({path:"Outputs",message:`Template has ${Object.keys(c).length} outputs (limit is 200)`,severity:"error"});return{valid:n.length===0,errors:n,warnings:r,info:i}}var v={Ref:(e)=>({Ref:e}),GetAtt:(e,n)=>({"Fn::GetAtt":[e,n]}),Sub:(e,n)=>{if(n)return{"Fn::Sub":[e,n]};return{"Fn::Sub":e}},Join:(e,n)=>({"Fn::Join":[e,n]}),Select:(e,n)=>({"Fn::Select":[e,n]}),Split:(e,n)=>({"Fn::Split":[e,n]}),GetAZs:(e="")=>({"Fn::GetAZs":e}),ImportValue:(e)=>({"Fn::ImportValue":e}),If:(e,n,r)=>({"Fn::If":[e,n,r]}),Equals:(e,n)=>({"Fn::Equals":[e,n]}),And:(...e)=>({"Fn::And":e}),Or:(...e)=>({"Fn::Or":e}),Not:(e)=>({"Fn::Not":[e]}),Base64:(e)=>({"Fn::Base64":e})},vu={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 l(e){let{slug:n,environment:r,resourceType:i,timestamp:s,suffix:a}=e,c=[n,r,i];if(s)c.push(s);if(a)c.push(a);return c.join("-")}function o(e){return e.split("-").map((n)=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}function Mm(){return Date.now().toString()}function Um(e){return e.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function T(e,n){return e.project.stackName??`${e.project.slug}-${n}`}function wa(e,n,r,i){return r.stackName??`${e.project.slug}-${i}-${n}-site`}function Aa(e,n){return`${e.project.slug}-${n}`}function Ra(e,n,r,i){if(i)return i;if(r==="main")return`${e}-${n}-site`;return`${e}-${n}-${r}`}function Bm(e,n,r,i){return i??`${e}-${n}-${r}`}function Fm(e,n){return`${e}-${n}-deploy`}function Le(e,n){return`${e.project.slug}-${n}-app`}function Ia(e,n){return`${e}-${n}-deployments`}function Vi(e,n){return`${e}-${n}-assets`}class Cu{nodes=new Map;addResource(e,n){let r=this.extractDependencies(n);this.nodes.set(e,{logicalId:e,resource:n,dependencies:r})}extractDependencies(e){let n=new Set;if(e.DependsOn)if(Array.isArray(e.DependsOn))e.DependsOn.forEach((r)=>n.add(r));else n.add(e.DependsOn);return this.findReferences(e.Properties||{},n),n}findReferences(e,n){if(!e||typeof e!=="object")return;if("Ref"in e&&typeof e.Ref==="string"){if(!e.Ref.startsWith("AWS::"))n.add(e.Ref)}if("Fn::GetAtt"in e&&Array.isArray(e["Fn::GetAtt"]))n.add(e["Fn::GetAtt"][0]);for(let r of Object.values(e))if(typeof r==="object")this.findReferences(r,n)}topologicalSort(){let e=[],n=new Set,r=new Set,i=(s)=>{if(n.has(s))return;if(r.has(s))throw Error(`Circular dependency detected: ${s}`);r.add(s);let a=this.nodes.get(s);if(a)for(let c of a.dependencies)i(c);r.delete(s),n.add(s),e.push(s)};for(let s of this.nodes.keys())i(s);return e}validate(){for(let[e,n]of this.nodes.entries())for(let r of n.dependencies)if(!this.nodes.has(r))throw Error(`Resource "${e}" depends on "${r}" which does not exist`)}getDependents(e){let n=[];for(let[r,i]of this.nodes.entries())if(i.dependencies.has(e))n.push(r);return n}}function jm(e,n){let r=[],i=[],s=[],a=[],c=[],u=e.Resources||{},d=n.Resources||{},m=new Set([...Object.keys(u),...Object.keys(d)]);for(let g of m){let y=u[g],f=d[g];if(!y&&f)r.push({logicalId:g,action:"add",resourceType:f.Type});else if(y&&!f)i.push({logicalId:g,action:"remove",resourceType:y.Type});else if(y&&f)if(y.Type!==f.Type)a.push({logicalId:g,action:"replace",resourceType:f.Type,reason:`Type changed from ${y.Type} to ${f.Type}`});else{let h=an(y.Properties||{},f.Properties||{});if(h.length>0)if(Ur(y.Type,h))a.push({logicalId:g,action:"replace",resourceType:f.Type,changes:h,reason:"Property changes require replacement"});else s.push({logicalId:g,action:"update",resourceType:f.Type,changes:h});else c.push(g)}}let p=Kr([...i,...a,...s]);return{added:r,removed:i,updated:s,replaced:a,unchanged:c,summary:{totalChanges:r.length+i.length+s.length+a.length,requiresReplacement:a.length>0,dangerousChanges:p}}}function an(e,n,r=""){let i=[],s=new Set([...Object.keys(e),...Object.keys(n)]);for(let a of s){let c=r?`${r}.${a}`:a,u=e[a],d=n[a];if(u===void 0&&d!==void 0)i.push({path:c,oldValue:void 0,newValue:d});else if(u!==void 0&&d===void 0)i.push({path:c,oldValue:u,newValue:void 0});else if(typeof u!==typeof d)i.push({path:c,oldValue:u,newValue:d});else if(typeof u==="object"&&u!==null)if(Array.isArray(u)&&Array.isArray(d)){if(JSON.stringify(u)!==JSON.stringify(d))i.push({path:c,oldValue:u,newValue:d})}else if(!Array.isArray(u)&&!Array.isArray(d)){let m=an(u,d,c);i.push(...m)}else i.push({path:c,oldValue:u,newValue:d});else if(u!==d)i.push({path:c,oldValue:u,newValue:d})}return i}function Ur(e,n){let i={"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(!i)return!1;for(let s of n){let a=s.path.split(".")[0];if(i.has(a))return!0}return!1}function Kr(e){let n=[];for(let r of e){if(r.action==="remove"&&(r.resourceType==="AWS::RDS::DBInstance"||r.resourceType==="AWS::DynamoDB::Table"||r.resourceType==="AWS::ElastiCache::CacheCluster"))n.push(`Removing ${r.resourceType} ${r.logicalId} - data loss risk!`);if(r.action==="replace"&&(r.resourceType==="AWS::RDS::DBInstance"||r.resourceType==="AWS::DynamoDB::Table"))n.push(`Replacing ${r.resourceType} ${r.logicalId} - data loss risk!`);if((r.action==="remove"||r.action==="replace")&&r.resourceType==="AWS::S3::Bucket")n.push(`${r.action==="remove"?"Removing":"Replacing"} S3 bucket ${r.logicalId} - data loss risk!`);if(r.action==="replace"&&r.resourceType==="AWS::EC2::Instance")n.push(`Replacing EC2 instance ${r.logicalId} - downtime expected`);if(r.action==="update"&&r.resourceType==="AWS::EC2::SecurityGroup")n.push(`Updating security group ${r.logicalId} - may affect connectivity`);if((r.action==="update"||r.action==="replace")&&(r.resourceType==="AWS::IAM::Role"||r.resourceType==="AWS::IAM::Policy"))n.push(`Modifying IAM ${r.resourceType.split("::")[2]} ${r.logicalId} - may affect permissions`)}return n}function Vm(e){let n=[];if(n.push(`=== Stack Update Analysis ===
|
|
7
7
|
`),e.summary.totalChanges===0)return n.push(`No changes detected.
|
|
8
8
|
`),n.join(`
|
|
9
9
|
`);if(n.push(`Total changes: ${e.summary.totalChanges}`),n.push(`Requires replacement: ${e.summary.requiresReplacement?"Yes":"No"}
|
|
10
10
|
`),e.summary.dangerousChanges.length>0){n.push("⚠️ DANGEROUS CHANGES DETECTED:");for(let r of e.summary.dangerousChanges)n.push(` • ${r}`);n.push("")}if(e.added.length>0){n.push(`✅ Resources to Add (${e.added.length}):`);for(let r of e.added)n.push(` + ${r.logicalId} (${r.resourceType})`);n.push("")}if(e.removed.length>0){n.push(`❌ Resources to Remove (${e.removed.length}):`);for(let r of e.removed)n.push(` - ${r.logicalId} (${r.resourceType})`);n.push("")}if(e.replaced.length>0){n.push(`\uD83D\uDD04 Resources to Replace (${e.replaced.length}):`);for(let r of e.replaced){if(n.push(` ~ ${r.logicalId} (${r.resourceType})`),r.reason)n.push(` Reason: ${r.reason}`);if(r.changes){for(let i of r.changes.slice(0,3))n.push(` • ${i.path}: ${JSON.stringify(i.oldValue)} → ${JSON.stringify(i.newValue)}`);if(r.changes.length>3)n.push(` ... and ${r.changes.length-3} more changes`)}}n.push("")}if(e.updated.length>0){n.push(`\uD83D\uDCDD Resources to Update (${e.updated.length}):`);for(let r of e.updated)if(n.push(` ~ ${r.logicalId} (${r.resourceType})`),r.changes){for(let i of r.changes.slice(0,3))n.push(` • ${i.path}: ${JSON.stringify(i.oldValue)} → ${JSON.stringify(i.newValue)}`);if(r.changes.length>3)n.push(` ... and ${r.changes.length-3} more changes`)}n.push("")}if(e.unchanged.length>0)n.push(`⚪ Unchanged Resources (${e.unchanged.length})`);return n.join(`
|
|
11
|
-
`)}import{existsSync as _e,readdirSync as Pr}from"node:fs";import{join as ue}from"node:path";class He{static createBucket(e){let{name:n,bucketName:r,slug:i,environment:s,public:a=!1,versioning:c=!1,website:u=!1,encryption:d=!0,intelligentTiering:m=!1,cors:p,lifecycleRules:g}=e,y=r??l({slug:i,environment:s,resourceType:"s3",suffix:n}),f=o(y),h={Type:"AWS::S3::Bucket",Properties:{BucketName:y}};if(d)h.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(c)h.Properties.VersioningConfiguration={Status:"Enabled"};if(u)h.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!a)h.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(p&&p.length>0)h.Properties.CorsConfiguration={CorsRules:p.map((A)=>({AllowedOrigins:A.allowedOrigins,AllowedMethods:A.allowedMethods,AllowedHeaders:A.allowedHeaders,MaxAge:A.maxAge}))};if(g&&g.length>0)h.Properties.LifecycleConfiguration={Rules:g.map((A)=>({Id:A.id,Status:A.enabled?"Enabled":"Disabled",ExpirationInDays:A.expirationDays,Transitions:A.transitions?.map((R)=>({TransitionInDays:R.days,StorageClass:R.storageClass}))}))};if(m&&g){let A={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!h.Properties.LifecycleConfiguration)h.Properties.LifecycleConfiguration={Rules:[]};h.Properties.LifecycleConfiguration.Rules.push({Id:A.id,Status:"Enabled",Transitions:A.transitions?.map((R)=>({TransitionInDays:R.days,StorageClass:R.storageClass}))})}let S;if(a)S={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:v.Ref(f),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[v.Join("",[v.GetAtt(f,"Arn"),"/*"])]}]}}};return{bucket:h,bucketPolicy:S,logicalId:f}}static enableVersioning(e){if(!e.Properties)e.Properties={};return e.Properties.VersioningConfiguration={Status:"Enabled"},e}static enableWebsiteHosting(e,n="index.html",r="error.html"){if(!e.Properties)e.Properties={};return e.Properties.WebsiteConfiguration={IndexDocument:n,ErrorDocument:r},e}static setLifecycleRules(e,n){if(!e.Properties)e.Properties={};return e.Properties.LifecycleConfiguration={Rules:n.map((r)=>({Id:r.id,Status:r.enabled?"Enabled":"Disabled",ExpirationInDays:r.expirationDays,Transitions:r.transitions?.map((i)=>({TransitionInDays:i.days,StorageClass:i.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,n){if(!e.Properties)e.Properties={};if(!e.Properties.NotificationConfiguration)e.Properties.NotificationConfiguration={};if(!e.Properties.NotificationConfiguration.LambdaConfigurations)e.Properties.NotificationConfiguration.LambdaConfigurations=[];let r={Event:n.events[0],Function:n.functionArn};if(n.filter)r.Filter={S3Key:{Rules:[...n.filter.prefix?[{Name:"prefix",Value:n.filter.prefix}]:[],...n.filter.suffix?[{Name:"suffix",Value:n.filter.suffix}]:[]]}};for(let i of n.events){let s={...r,Event:i};e.Properties.NotificationConfiguration.LambdaConfigurations.push(s)}return e}static Notifications={onObjectCreated:(e)=>({functionArn:e,events:["s3:ObjectCreated:*"]}),onObjectRemoved:(e)=>({functionArn:e,events:["s3:ObjectRemoved:*"]}),onImageUpload:(e,n)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:n,suffix:".jpg"}}),onFileType:(e,n,r)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:r,suffix:n}}),onFolderUpload:(e,n)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:n.endsWith("/")?n:`${n}/`}})};static createBackupPlan(e){let{name:n,slug:r,environment:i,bucketLogicalIds:s,retentionDays:a,schedule:c="cron(0 5 * * ? *)",vaultName:u,enableContinuousBackup:d=!1,moveToColdStorageAfterDays:m}=e,p=u||l({slug:r,environment:i,resourceType:"backup-vault",suffix:n}),g=o(p),y={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:p}},f=l({slug:r,environment:i,resourceType:"backup-role",suffix:n}),h=o(f),S={Type:"AWS::IAM::Role",Properties:{RoleName:f,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"]}},A=l({slug:r,environment:i,resourceType:"backup-plan",suffix:n}),R=o(A),P={DeleteAfterDays:a};if(m&&m<a)P.MoveToColdStorageAfterDays=m;let C={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:A,BackupPlanRule:[{RuleName:`${n}-daily-backup`,TargetBackupVault:v.Ref(g),ScheduleExpression:c,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:P,EnableContinuousBackup:d}]}}},E=l({slug:r,environment:i,resourceType:"backup-selection",suffix:n}),D=o(E),x=s.map((B)=>v.GetAtt(B,"Arn")),L={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:v.Ref(R),BackupSelection:{SelectionName:E,IamRoleArn:v.GetAtt(h,"Arn"),Resources:x}}};return{vault:y,plan:C,selection:L,role:S,vaultLogicalId:g,planLogicalId:R,selectionLogicalId:D,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:n,environment:r,sourceDomain:i,targetDomain:s,protocol:a="https"}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"www-redirect"}),u=o(c),d={Type:"AWS::S3::Bucket",Properties:{BucketName:i,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:s,Protocol:a}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},m={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:v.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[v.Join("",[v.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:d,bucketPolicy:m,logicalId:u}}static createDocsBucket(e){let{slug:n,environment:r,domain:i}=e,s=i||l({slug:n,environment:r,resourceType:"s3",suffix:"docs"}),a=o(s);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:s,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:a}}static createEmailBucket(e){let{slug:n,environment:r}=e,i=l({slug:n,environment:r,resourceType:"s3",suffix:"email"}),s=o(i),a={Type:"AWS::S3::Bucket",Properties:{BucketName:i,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"EmailRetention",Status:"Enabled",ExpirationInDays:90,Transitions:[{TransitionInDays:30,StorageClass:"STANDARD_IA"}]}]}}},c={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:v.Ref(s),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:v.Join("",[v.GetAtt(s,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":v.Ref("AWS::AccountId")}}}]}}};return{bucket:a,bucketPolicy:c,logicalId:s}}static docsExist(e={}){let{projectRoot:n=process.cwd(),docsPaths:r=["docs","documentation","doc"]}=e;for(let i of r){let s=ue(n,i);if(_e(s)){let a=["dist","build",".bunpress/dist","_site","out","public"];for(let c of a){let u=ue(s,c);if(_e(u))try{if(Pr(u).length>0)return{exists:!0,path:s,hasDistFolder:!0,distPath:u}}catch{}}return{exists:!0,path:s,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(e){let n=He.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!n.exists)return{bucket:null,logicalId:null,docsInfo:n};let r=He.createDocsBucket({slug:e.slug,environment:e.environment,domain:e.domain});return{bucket:r.bucket,bucketPolicy:r.bucketPolicy,logicalId:r.logicalId,docsInfo:n}}static createPrivateBucket(e){let{slug:n,environment:r,enableVersioning:i=!0,retentionDays:s,encryptionKeyArn:a}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"private"}),u=o(c);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:c,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:a?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:a}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:i?{Status:"Enabled"}:void 0,LifecycleConfiguration:s?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:s}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:u}}static checkSourcePaths(e={}){let{projectRoot:n=process.cwd(),paths:r={}}=e,i=r.web||"views/web/dist",s=r.docs||"docs/dist",a=r.private||"private";return{web:{exists:_e(ue(n,i)),path:ue(n,i)},docs:{exists:_e(ue(n,s)),path:ue(n,s)},private:{exists:_e(ue(n,a)),path:ue(n,a)}}}static createDeploymentBuckets(e){let{slug:n,environment:r,domain:i,projectRoot:s,paths:a}=e,c=He.checkSourcePaths({projectRoot:s,paths:a}),u={},d={web:!1,docs:!1,private:!1},m=He.createBucket({name:"web",slug:n,environment:r,public:!1,versioning:!1,encryption:!0});if(u[m.logicalId]=m.bucket,d.web=!0,c.docs.exists){let p=He.createDocsBucket({slug:n,environment:r,domain:i?`docs.${i}`:void 0});if(u[p.logicalId]=p.bucket,p.bucketPolicy)u[`${p.logicalId}Policy`]=p.bucketPolicy;d.docs=!0}if(c.private.exists){let p=He.createPrivateBucket({slug:n,environment:r,enableVersioning:!0});u[p.logicalId]=p.bucket,d.private=!0}return{resources:u,created:d,sourcePaths:c}}}class Dt{static createRepository(e){let{name:n,slug:r,environment:i,scanOnPush:s=!0,imageMutability:a="MUTABLE",encryption:c="AES256",kmsKey:u,lifecyclePolicy:d,tags:m}=e,p=l({slug:r,environment:i,resourceType:"ecr",suffix:n}),g=o(p),y={Type:"AWS::ECR::Repository",Properties:{RepositoryName:p,ImageTagMutability:a,ImageScanningConfiguration:{ScanOnPush:s},EncryptionConfiguration:{EncryptionType:c,...u&&c==="KMS"?{KmsKey:u}:{}}}};if(d)y.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Dt.generateLifecyclePolicy(d))};if(m)y.Properties.Tags=Object.entries(m).map(([f,h])=>({Key:f,Value:h}));return{repository:y,logicalId:g}}static generateLifecyclePolicy(e){let n=[];if(e.untaggedImageExpireDays!==void 0)n.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)n.push({rulePriority:n.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount},action:{type:"expire"}});if(e.maxImageAgeDays!==void 0)n.push({rulePriority:n.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:n}}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,n){if(!e.Properties)e.Properties={};return e.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Dt.generateLifecyclePolicy(n))},e}static addCrossAccountAccess(e,n){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:n.map((r)=>`arn:aws:iam::${r}:root`)},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]},e}static addLambdaAccess(e){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"LambdaECRImageRetrievalPolicy",Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]},e}static generateBunDockerfile(e){let{baseImage:n="oven/bun:1-debian",serverPath:r,port:i=3000,additionalDirs:s=[],healthCheckEndpoint:a="/health",nodeCompatible:c=!1,envVars:u={},buildCommands:d=[],runCommand:m}=e,p=["app","config",...s],g=m||`bun run ${r}`,y=`# Multi-stage build for Bun application
|
|
11
|
+
`)}import{existsSync as Ve,readdirSync as Qr}from"node:fs";import{join as me}from"node:path";class Ge{static createBucket(e){let{name:n,bucketName:r,slug:i,environment:s,public:a=!1,versioning:c=!1,website:u=!1,encryption:d=!0,intelligentTiering:m=!1,cors:p,lifecycleRules:g}=e,y=r??l({slug:i,environment:s,resourceType:"s3",suffix:n}),f=o(y),h={Type:"AWS::S3::Bucket",Properties:{BucketName:y}};if(d)h.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(c)h.Properties.VersioningConfiguration={Status:"Enabled"};if(u)h.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!a)h.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(p&&p.length>0)h.Properties.CorsConfiguration={CorsRules:p.map((A)=>({AllowedOrigins:A.allowedOrigins,AllowedMethods:A.allowedMethods,AllowedHeaders:A.allowedHeaders,MaxAge:A.maxAge}))};if(g&&g.length>0)h.Properties.LifecycleConfiguration={Rules:g.map((A)=>({Id:A.id,Status:A.enabled?"Enabled":"Disabled",ExpirationInDays:A.expirationDays,Transitions:A.transitions?.map((R)=>({TransitionInDays:R.days,StorageClass:R.storageClass}))}))};if(m&&g){let A={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!h.Properties.LifecycleConfiguration)h.Properties.LifecycleConfiguration={Rules:[]};h.Properties.LifecycleConfiguration.Rules.push({Id:A.id,Status:"Enabled",Transitions:A.transitions?.map((R)=>({TransitionInDays:R.days,StorageClass:R.storageClass}))})}let S;if(a)S={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:v.Ref(f),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[v.Join("",[v.GetAtt(f,"Arn"),"/*"])]}]}}};return{bucket:h,bucketPolicy:S,logicalId:f}}static enableVersioning(e){if(!e.Properties)e.Properties={};return e.Properties.VersioningConfiguration={Status:"Enabled"},e}static enableWebsiteHosting(e,n="index.html",r="error.html"){if(!e.Properties)e.Properties={};return e.Properties.WebsiteConfiguration={IndexDocument:n,ErrorDocument:r},e}static setLifecycleRules(e,n){if(!e.Properties)e.Properties={};return e.Properties.LifecycleConfiguration={Rules:n.map((r)=>({Id:r.id,Status:r.enabled?"Enabled":"Disabled",ExpirationInDays:r.expirationDays,Transitions:r.transitions?.map((i)=>({TransitionInDays:i.days,StorageClass:i.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,n){if(!e.Properties)e.Properties={};if(!e.Properties.NotificationConfiguration)e.Properties.NotificationConfiguration={};if(!e.Properties.NotificationConfiguration.LambdaConfigurations)e.Properties.NotificationConfiguration.LambdaConfigurations=[];let r={Event:n.events[0],Function:n.functionArn};if(n.filter)r.Filter={S3Key:{Rules:[...n.filter.prefix?[{Name:"prefix",Value:n.filter.prefix}]:[],...n.filter.suffix?[{Name:"suffix",Value:n.filter.suffix}]:[]]}};for(let i of n.events){let s={...r,Event:i};e.Properties.NotificationConfiguration.LambdaConfigurations.push(s)}return e}static Notifications={onObjectCreated:(e)=>({functionArn:e,events:["s3:ObjectCreated:*"]}),onObjectRemoved:(e)=>({functionArn:e,events:["s3:ObjectRemoved:*"]}),onImageUpload:(e,n)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:n,suffix:".jpg"}}),onFileType:(e,n,r)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:r,suffix:n}}),onFolderUpload:(e,n)=>({functionArn:e,events:["s3:ObjectCreated:*"],filter:{prefix:n.endsWith("/")?n:`${n}/`}})};static createBackupPlan(e){let{name:n,slug:r,environment:i,bucketLogicalIds:s,retentionDays:a,schedule:c="cron(0 5 * * ? *)",vaultName:u,enableContinuousBackup:d=!1,moveToColdStorageAfterDays:m}=e,p=u||l({slug:r,environment:i,resourceType:"backup-vault",suffix:n}),g=o(p),y={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:p}},f=l({slug:r,environment:i,resourceType:"backup-role",suffix:n}),h=o(f),S={Type:"AWS::IAM::Role",Properties:{RoleName:f,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"]}},A=l({slug:r,environment:i,resourceType:"backup-plan",suffix:n}),R=o(A),P={DeleteAfterDays:a};if(m&&m<a)P.MoveToColdStorageAfterDays=m;let C={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:A,BackupPlanRule:[{RuleName:`${n}-daily-backup`,TargetBackupVault:v.Ref(g),ScheduleExpression:c,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:P,EnableContinuousBackup:d}]}}},E=l({slug:r,environment:i,resourceType:"backup-selection",suffix:n}),D=o(E),x=s.map((B)=>v.GetAtt(B,"Arn")),L={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:v.Ref(R),BackupSelection:{SelectionName:E,IamRoleArn:v.GetAtt(h,"Arn"),Resources:x}}};return{vault:y,plan:C,selection:L,role:S,vaultLogicalId:g,planLogicalId:R,selectionLogicalId:D,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:n,environment:r,sourceDomain:i,targetDomain:s,protocol:a="https"}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"www-redirect"}),u=o(c),d={Type:"AWS::S3::Bucket",Properties:{BucketName:i,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:s,Protocol:a}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},m={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:v.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[v.Join("",[v.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:d,bucketPolicy:m,logicalId:u}}static createDocsBucket(e){let{slug:n,environment:r,domain:i}=e,s=i||l({slug:n,environment:r,resourceType:"s3",suffix:"docs"}),a=o(s);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:s,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:a}}static createEmailBucket(e){let{slug:n,environment:r}=e,i=l({slug:n,environment:r,resourceType:"s3",suffix:"email"}),s=o(i),a={Type:"AWS::S3::Bucket",Properties:{BucketName:i,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"EmailRetention",Status:"Enabled",ExpirationInDays:90,Transitions:[{TransitionInDays:30,StorageClass:"STANDARD_IA"}]}]}}},c={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:v.Ref(s),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:v.Join("",[v.GetAtt(s,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":v.Ref("AWS::AccountId")}}}]}}};return{bucket:a,bucketPolicy:c,logicalId:s}}static docsExist(e={}){let{projectRoot:n=process.cwd(),docsPaths:r=["docs","documentation","doc"]}=e;for(let i of r){let s=me(n,i);if(Ve(s)){let a=["dist","build",".bunpress/dist","_site","out","public"];for(let c of a){let u=me(s,c);if(Ve(u))try{if(Qr(u).length>0)return{exists:!0,path:s,hasDistFolder:!0,distPath:u}}catch{}}return{exists:!0,path:s,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(e){let n=Ge.docsExist({projectRoot:e.projectRoot,docsPaths:e.docsPaths});if(!n.exists)return{bucket:null,logicalId:null,docsInfo:n};let r=Ge.createDocsBucket({slug:e.slug,environment:e.environment,domain:e.domain});return{bucket:r.bucket,bucketPolicy:r.bucketPolicy,logicalId:r.logicalId,docsInfo:n}}static createPrivateBucket(e){let{slug:n,environment:r,enableVersioning:i=!0,retentionDays:s,encryptionKeyArn:a}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"private"}),u=o(c);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:c,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:a?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:a}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:i?{Status:"Enabled"}:void 0,LifecycleConfiguration:s?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:s}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:u}}static checkSourcePaths(e={}){let{projectRoot:n=process.cwd(),paths:r={}}=e,i=r.web||"views/web/dist",s=r.docs||"docs/dist",a=r.private||"private";return{web:{exists:Ve(me(n,i)),path:me(n,i)},docs:{exists:Ve(me(n,s)),path:me(n,s)},private:{exists:Ve(me(n,a)),path:me(n,a)}}}static createDeploymentBuckets(e){let{slug:n,environment:r,domain:i,projectRoot:s,paths:a}=e,c=Ge.checkSourcePaths({projectRoot:s,paths:a}),u={},d={web:!1,docs:!1,private:!1},m=Ge.createBucket({name:"web",slug:n,environment:r,public:!1,versioning:!1,encryption:!0});if(u[m.logicalId]=m.bucket,d.web=!0,c.docs.exists){let p=Ge.createDocsBucket({slug:n,environment:r,domain:i?`docs.${i}`:void 0});if(u[p.logicalId]=p.bucket,p.bucketPolicy)u[`${p.logicalId}Policy`]=p.bucketPolicy;d.docs=!0}if(c.private.exists){let p=Ge.createPrivateBucket({slug:n,environment:r,enableVersioning:!0});u[p.logicalId]=p.bucket,d.private=!0}return{resources:u,created:d,sourcePaths:c}}}class Nt{static createRepository(e){let{name:n,slug:r,environment:i,scanOnPush:s=!0,imageMutability:a="MUTABLE",encryption:c="AES256",kmsKey:u,lifecyclePolicy:d,tags:m}=e,p=l({slug:r,environment:i,resourceType:"ecr",suffix:n}),g=o(p),y={Type:"AWS::ECR::Repository",Properties:{RepositoryName:p,ImageTagMutability:a,ImageScanningConfiguration:{ScanOnPush:s},EncryptionConfiguration:{EncryptionType:c,...u&&c==="KMS"?{KmsKey:u}:{}}}};if(d)y.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Nt.generateLifecyclePolicy(d))};if(m)y.Properties.Tags=Object.entries(m).map(([f,h])=>({Key:f,Value:h}));return{repository:y,logicalId:g}}static generateLifecyclePolicy(e){let n=[];if(e.untaggedImageExpireDays!==void 0)n.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)n.push({rulePriority:n.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:e.maxImageCount},action:{type:"expire"}});if(e.maxImageAgeDays!==void 0)n.push({rulePriority:n.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:e.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:n}}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,n){if(!e.Properties)e.Properties={};return e.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(Nt.generateLifecyclePolicy(n))},e}static addCrossAccountAccess(e,n){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:n.map((r)=>`arn:aws:iam::${r}:root`)},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]},e}static addLambdaAccess(e){if(!e.Properties)e.Properties={};return e.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"LambdaECRImageRetrievalPolicy",Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]},e}static generateBunDockerfile(e){let{baseImage:n="oven/bun:1-debian",serverPath:r,port:i=3000,additionalDirs:s=[],healthCheckEndpoint:a="/health",nodeCompatible:c=!1,envVars:u={},buildCommands:d=[],runCommand:m}=e,p=["app","config",...s],g=m||`bun run ${r}`,y=`# Multi-stage build for Bun application
|
|
12
12
|
# Generated by ts-cloud
|
|
13
13
|
|
|
14
14
|
# Builder stage
|
|
@@ -62,7 +62,7 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\
|
|
|
62
62
|
|
|
63
63
|
# Start application
|
|
64
64
|
CMD ["bun", "run", "${r}"]
|
|
65
|
-
`,y}static generateDockerBuildCommands(e){let{repositoryUri:n,tag:r="latest",dockerfilePath:i="Dockerfile",context:s=".",additionalTags:a=[],buildArgs:c={},platform:u="linux/amd64",noCache:d=!1}=e,m=`${n}:${r}`,p=[r,...a],g=`docker build -f ${i} -t ${m}`;if(u)g+=` --platform ${u}`;if(d)g+=" --no-cache";for(let[h,S]of Object.entries(c))g+=` --build-arg ${h}=${S}`;g+=` ${s}`;let y=p.slice(1).map((h)=>`docker tag ${m} ${n}:${h}`),f=p.map((h)=>`docker push ${n}:${h}`);return{build:g,tag:y,push:f,all:[g,...y,...f]}}static generateEcrLoginCommand(e,n){return`aws ecr get-login-password --region ${e} | docker login --username AWS --password-stdin ${n}.dkr.ecr.${e}.amazonaws.com`}static buildRepositoryUri(e){return`${e.accountId}.dkr.ecr.${e.region}.amazonaws.com/${e.repositoryName}`}static generateImageTags(e){let n=["latest"];if(e.version){n.push(e.version);let r=e.version.split(".");if(r.length>=2)n.push(`${r[0]}.${r[1]}`);if(r.length>=1)n.push(r[0])}if(e.gitSha)n.push(e.gitSha.substring(0,7)),n.push(e.gitSha);if(e.gitBranch){let r=e.gitBranch.replace(/[^a-zA-Z0-9.-]/g,"-").replace(/^-+|-+$/g,"");n.push(r)}if(e.environment)n.push(e.environment);if(e.timestamp){let r=new Date().toISOString().replace(/[:.]/g,"-").substring(0,19);n.push(r)}return[...new Set(n)]}static DeploymentWorkflow={generateDeployScript:(e)=>{let n=
|
|
65
|
+
`,y}static generateDockerBuildCommands(e){let{repositoryUri:n,tag:r="latest",dockerfilePath:i="Dockerfile",context:s=".",additionalTags:a=[],buildArgs:c={},platform:u="linux/amd64",noCache:d=!1}=e,m=`${n}:${r}`,p=[r,...a],g=`docker build -f ${i} -t ${m}`;if(u)g+=` --platform ${u}`;if(d)g+=" --no-cache";for(let[h,S]of Object.entries(c))g+=` --build-arg ${h}=${S}`;g+=` ${s}`;let y=p.slice(1).map((h)=>`docker tag ${m} ${n}:${h}`),f=p.map((h)=>`docker push ${n}:${h}`);return{build:g,tag:y,push:f,all:[g,...y,...f]}}static generateEcrLoginCommand(e,n){return`aws ecr get-login-password --region ${e} | docker login --username AWS --password-stdin ${n}.dkr.ecr.${e}.amazonaws.com`}static buildRepositoryUri(e){return`${e.accountId}.dkr.ecr.${e.region}.amazonaws.com/${e.repositoryName}`}static generateImageTags(e){let n=["latest"];if(e.version){n.push(e.version);let r=e.version.split(".");if(r.length>=2)n.push(`${r[0]}.${r[1]}`);if(r.length>=1)n.push(r[0])}if(e.gitSha)n.push(e.gitSha.substring(0,7)),n.push(e.gitSha);if(e.gitBranch){let r=e.gitBranch.replace(/[^a-zA-Z0-9.-]/g,"-").replace(/^-+|-+$/g,"");n.push(r)}if(e.environment)n.push(e.environment);if(e.timestamp){let r=new Date().toISOString().replace(/[:.]/g,"-").substring(0,19);n.push(r)}return[...new Set(n)]}static DeploymentWorkflow={generateDeployScript:(e)=>{let n=Nt.buildRepositoryUri({accountId:e.accountId,region:e.region,repositoryName:e.repositoryName}),r=e.tags||["latest"],i=r[0];return`#!/bin/bash
|
|
66
66
|
set -e
|
|
67
67
|
|
|
68
68
|
# Configuration
|
|
@@ -73,7 +73,7 @@ IMAGE_URI="${n}"
|
|
|
73
73
|
DOCKERFILE="${e.dockerfilePath||"Dockerfile"}"
|
|
74
74
|
|
|
75
75
|
echo "=== ECR Login ==="
|
|
76
|
-
${
|
|
76
|
+
${Nt.generateEcrLoginCommand(e.region,e.accountId)}
|
|
77
77
|
|
|
78
78
|
echo "=== Building Image ==="
|
|
79
79
|
docker build -f $DOCKERFILE -t $IMAGE_URI:${i} --platform linux/amd64 .
|
|
@@ -91,7 +91,7 @@ echo "Image: $IMAGE_URI:${i}"
|
|
|
91
91
|
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
|
|
92
92
|
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
|
|
93
93
|
${JSON.stringify(n,null,2).replace(/"/g,"").replace(/,\n/g,`
|
|
94
|
-
`)}`}};static DockerfileTemplates={bunServer:(e,n=3000)=>Dt.generateBunDockerfile({serverPath:e,port:n}),bunWithBuild:(e,n,r=3000)=>Dt.generateBunDockerfile({serverPath:e,port:r,buildCommands:[n]}),bunFullStack:(e,n=3000)=>Dt.generateBunDockerfile({serverPath:e,port:n,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,n=3000)=>Dt.generateBunDockerfile({serverPath:e,port:n,healthCheckEndpoint:"/api/health"})}}var va=[400,403,404,416,429,500,502,503,504],al=[500,502,503,504],cl=["GET","HEAD","OPTIONS"],Nm="-failover-group",ll=["default","media-quality-based"],dl={min:1,max:3},ul={min:1,max:10};function Yo(e){if(e===void 0)return[...al];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${va.join(", ")}). Omit it to use the default ${al.join(", ")}.`);let n=e.filter((r)=>!va.includes(r));if(n.length>0)throw Error(`CloudFront origin failover: ${n.join(", ")} ${n.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${va.join(", ")}.`);return[...new Set(e)].sort((r,i)=>r-i)}function Ca(e){let{primaryOriginId:n,secondaryOriginId:r}=e;if(!n||!r)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(n===r)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${n}")`);let i=Yo(e.statusCodes);return nn(e.selectionCriteria),{Id:e.groupId??`${n}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:i.length,Items:i}},Members:{Quantity:2,Items:[{OriginId:n},{OriginId:r}]},...e.selectionCriteria?{SelectionCriteria:e.selectionCriteria}:{}}}function nn(e,n="the origin group"){if(e===void 0)return;if(!ll.includes(e))throw Error(`CloudFront origin failover: ${n} has selection criteria ${JSON.stringify(e)}. Allowed: ${ll.join(", ")}.`)}function Ze(e,n,r){if(typeof e!=="number"||!Number.isInteger(e)||e<n.min||e>n.max)throw Error(`CloudFront origin: ${r} must be a whole number from ${n.min} to ${n.max}, got ${JSON.stringify(e)}.`)}function st(e,n="the origin"){let r={};if(e?.connectionAttempts!==void 0)Ze(e.connectionAttempts,dl,`${n} connectionAttempts`),r.ConnectionAttempts=e.connectionAttempts;if(e?.connectionTimeout!==void 0)Ze(e.connectionTimeout,ul,`${n} connectionTimeout (seconds)`),r.ConnectionTimeout=e.connectionTimeout;return r}function Zo(e){return{Quantity:1,Items:[Ca(e)]}}function An(e,n="the cache behavior"){let i=(Array.isArray(e)?e:e?.Items??[]).filter((s)=>!cl.includes(s.toUpperCase()));if(i.length>0)throw Error(`CloudFront origin failover: ${n} allows ${i.join(", ")}, but a cache behavior that targets an origin group may only allow ${cl.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function ji(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}function We(e){if(!e)return[];if(Array.isArray(e))return e;return e.Items??[]}function se(e){return typeof e==="string"?e:void 0}var Er=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function Rn(e,n="the distribution"){let r=We(e.Origins),i=new Set(r.map((p)=>se(p.Id)).filter((p)=>!!p)),s=new Map(r.map((p)=>[se(p.Id)??"",p.DomainName])),a=r.some((p)=>se(p.Id)===void 0);for(let p of r){let g=se(p.Id)??"(unnamed origin)";if(p.ConnectionAttempts!==void 0)Ze(p.ConnectionAttempts,dl,`${n} origin "${g}" ConnectionAttempts`);if(p.ConnectionTimeout!==void 0)Ze(p.ConnectionTimeout,ul,`${n} origin "${g}" ConnectionTimeout (seconds)`)}let c=e.OriginGroups,u=We(c);if(c&&!Array.isArray(c)&&c.Quantity!==void 0&&c.Quantity!==u.length)throw Error(`CloudFront origin failover: ${n} OriginGroups.Quantity is ${c.Quantity} but it lists ${u.length} group(s).`);let d=new Set;for(let p of u){let g=se(p.Id);if(p.Id===void 0||p.Id==="")throw Error(`CloudFront origin failover: ${n} has an origin group without an Id.`);let y=`${n} origin group "${g??"(intrinsic id)"}"`;if(g){if(d.has(g))throw Error(`CloudFront origin failover: ${n} declares origin group "${g}" twice.`);if(i.has(g))throw Error(`CloudFront origin failover: ${y} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);d.add(g)}let f=p.Members,h=We(f);if(h.length!==2||f?.Quantity!==void 0&&f.Quantity!==h.length)throw Error(`CloudFront origin failover: ${y} must have exactly 2 members (a primary and a secondary), it has ${h.length}${f?.Quantity!==void 0&&f.Quantity!==h.length?` with Quantity ${f.Quantity}`:""}.`);let S=h.map((P)=>se(P.OriginId));for(let P of S)if(P&&!i.has(P)&&!a)throw Error(`CloudFront origin failover: ${y} lists member "${P}", which is not an origin of this distribution. Origins: ${[...i].join(", ")||"(none)"}.`);if(S[0]&&S[0]===S[1])throw Error(`CloudFront origin failover: ${y} lists "${S[0]}" as both primary and secondary.`);let A=p.FailoverCriteria?.StatusCodes,R=We(A);if(Yo(R),A?.Quantity!==void 0&&A.Quantity!==R.length)throw Error(`CloudFront origin failover: ${y} FailoverCriteria.StatusCodes.Quantity is ${A.Quantity} but it lists ${R.length} code(s).`);if(nn(p.SelectionCriteria,y),p.SelectionCriteria==="media-quality-based")for(let P of S){let C=P?se(s.get(P)):void 0;if(C&&!Er.test(C))throw Error(`CloudFront origin failover: ${y} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${P}" is ${C}. Use 'default'.`)}}let m=[];if(e.DefaultCacheBehavior)m.push({behavior:e.DefaultCacheBehavior,name:"the default cache behavior"});for(let p of We(e.CacheBehaviors))m.push({behavior:p,name:`the cache behavior for ${JSON.stringify(p.PathPattern)}`});for(let{behavior:p,name:g}of m){let y=se(p.TargetOriginId);if(!y)continue;if(d.has(y))An(p.AllowedMethods??["GET","HEAD"],`${g} of ${n} (origin group "${y}")`);else if(!i.has(y)&&!a&&u.every((f)=>se(f.Id)!==void 0))throw Error(`CloudFront: ${g} of ${n} targets "${y}", which is neither an origin nor an origin group of this distribution.`)}}class Ge{static createDistribution(e){let{slug:n,environment:r,origin:i,customDomain:s,certificateArn:a,errorPages:c,cachePolicy:u,edgeFunctions:d,http3:m=!1,comment:p,failoverOrigin:g}=e,y=l({slug:n,environment:r,resourceType:"cdn"}),f=o(y),h={Id:"DefaultOrigin",DomainName:i.domainName,OriginPath:i.originPath||"",...st(i,"the CDN origin")},S;if(i.type==="s3"){let R=`${f}OAC`;S={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${y}-oac`,Description:`Origin Access Control for ${y}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},h.OriginAccessControlId=v.Ref(R)}else if(i.type==="alb"||i.type==="custom")h.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let A={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:p||`CDN for ${y}`,DefaultRootObject:"index.html",Origins:[h],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:m?"http2and3":"http2"}}};if(s&&a)A.Properties.DistributionConfig.Aliases=[s],A.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:a,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(c&&c.length>0)A.Properties.DistributionConfig.CustomErrorResponses=c.map((R)=>({ErrorCode:R.errorCode,ResponseCode:R.responseCode,ResponsePagePath:R.responsePagePath}));if(d&&d.length>0)A.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=d.map((R)=>({EventType:R.event,LambdaFunctionARN:R.functionArn}));if(g)Ge.addOriginFailover(A,g);return{distribution:A,originAccessControl:S,logicalId:f}}static addOriginFailover(e,n){let r=e.Properties.DistributionConfig,i=r.DefaultCacheBehavior,s=i.TargetOriginId,a=n.id??"FailoverOrigin";if(r.OriginGroups&&r.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(An(i.AllowedMethods??["GET","HEAD"],"the default cache behavior"),r.Origins.some((p)=>p.Id===a))throw Error(`CloudFront origin failover: an origin with id "${a}" already exists`);let c=Ca({primaryOriginId:s,secondaryOriginId:a,statusCodes:n.statusCodes,selectionCriteria:n.selectionCriteria}),u=n.type??(ji(n.domainName)?"s3":"custom"),d={Id:a,DomainName:n.domainName,OriginPath:n.originPath||"",...st(n,"the failover origin")},m=st(n.primary,"the primary origin");if(Object.keys(m).length>0){let p=r.Origins.find((g)=>g.Id===s);if(p)Object.assign(p,m)}if(u==="s3"){let p=r.Origins.find((g)=>g.Id===s);if(d.S3OriginConfig={OriginAccessIdentity:""},p?.OriginAccessControlId)d.OriginAccessControlId=p.OriginAccessControlId}else d.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return r.Origins.push(d),r.OriginGroups={Quantity:1,Items:[c]},i.TargetOriginId=c.Id,Rn(r),e}static setCustomDomain(e,n,r){return e.Properties.DistributionConfig.Aliases=[n],e.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:r,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},e}static setErrorPages(e,n){return e.Properties.DistributionConfig.CustomErrorResponses=n.map((r)=>({ErrorCode:r.errorCode,ResponseCode:r.responseCode,ResponsePagePath:r.responsePagePath})),e}static enableHttp3(e){return e.Properties.DistributionConfig.HttpVersion="http2and3",e}static addEdgeFunction(e,n,r){if(!e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:n,LambdaFunctionARN:r}),e}static setCachePolicy(e,n){return e.Properties.DistributionConfig.Comment=`${e.Properties.DistributionConfig.Comment||""} (TTL: ${n.default||86400}s)`,e}static createSpaDistribution(e){return Ge.createDistribution({...e,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(e){let{slug:n,environment:r}=e,i=l({slug:n,environment:r,resourceType:"edge-docs"}),s=o(i),a=o(`${i}-role`),c=o(`${i}-version`),u={Type:"AWS::IAM::Role",Properties:{RoleName:`${i}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","edgelambda.amazonaws.com"]},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}},d=`
|
|
94
|
+
`)}`}};static DockerfileTemplates={bunServer:(e,n=3000)=>Nt.generateBunDockerfile({serverPath:e,port:n}),bunWithBuild:(e,n,r=3000)=>Nt.generateBunDockerfile({serverPath:e,port:r,buildCommands:[n]}),bunFullStack:(e,n=3000)=>Nt.generateBunDockerfile({serverPath:e,port:n,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,n=3000)=>Nt.generateBunDockerfile({serverPath:e,port:n,healthCheckEndpoint:"/api/health"})}}var Pa=[400,403,404,416,429,500,502,503,504],hl=[500,502,503,504],yl=["GET","HEAD","OPTIONS"],zm="-failover-group",bl=["default","media-quality-based"],Sl={min:1,max:3},vl={min:1,max:10};function ns(e){if(e===void 0)return[...hl];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${Pa.join(", ")}). Omit it to use the default ${hl.join(", ")}.`);let n=e.filter((r)=>!Pa.includes(r));if(n.length>0)throw Error(`CloudFront origin failover: ${n.join(", ")} ${n.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${Pa.join(", ")}.`);return[...new Set(e)].sort((r,i)=>r-i)}function Da(e){let{primaryOriginId:n,secondaryOriginId:r}=e;if(!n||!r)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(n===r)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${n}")`);let i=ns(e.statusCodes);return on(e.selectionCriteria),{Id:e.groupId??`${n}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:i.length,Items:i}},Members:{Quantity:2,Items:[{OriginId:n},{OriginId:r}]},...e.selectionCriteria?{SelectionCriteria:e.selectionCriteria}:{}}}function on(e,n="the origin group"){if(e===void 0)return;if(!bl.includes(e))throw Error(`CloudFront origin failover: ${n} has selection criteria ${JSON.stringify(e)}. Allowed: ${bl.join(", ")}.`)}function et(e,n,r){if(typeof e!=="number"||!Number.isInteger(e)||e<n.min||e>n.max)throw Error(`CloudFront origin: ${r} must be a whole number from ${n.min} to ${n.max}, got ${JSON.stringify(e)}.`)}function ct(e,n="the origin"){let r={};if(e?.connectionAttempts!==void 0)et(e.connectionAttempts,Sl,`${n} connectionAttempts`),r.ConnectionAttempts=e.connectionAttempts;if(e?.connectionTimeout!==void 0)et(e.connectionTimeout,vl,`${n} connectionTimeout (seconds)`),r.ConnectionTimeout=e.connectionTimeout;return r}function is(e){return{Quantity:1,Items:[Da(e)]}}function Rn(e,n="the cache behavior"){let i=(Array.isArray(e)?e:e?.Items??[]).filter((s)=>!yl.includes(s.toUpperCase()));if(i.length>0)throw Error(`CloudFront origin failover: ${n} allows ${i.join(", ")}, but a cache behavior that targets an origin group may only allow ${yl.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function zi(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}function Ue(e){if(!e)return[];if(Array.isArray(e))return e;return e.Items??[]}function oe(e){return typeof e==="string"?e:void 0}var Jr=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function In(e,n="the distribution"){let r=Ue(e.Origins),i=new Set(r.map((p)=>oe(p.Id)).filter((p)=>!!p)),s=new Map(r.map((p)=>[oe(p.Id)??"",p.DomainName])),a=r.some((p)=>oe(p.Id)===void 0);for(let p of r){let g=oe(p.Id)??"(unnamed origin)";if(p.ConnectionAttempts!==void 0)et(p.ConnectionAttempts,Sl,`${n} origin "${g}" ConnectionAttempts`);if(p.ConnectionTimeout!==void 0)et(p.ConnectionTimeout,vl,`${n} origin "${g}" ConnectionTimeout (seconds)`)}let c=e.OriginGroups,u=Ue(c);if(c&&!Array.isArray(c)&&c.Quantity!==void 0&&c.Quantity!==u.length)throw Error(`CloudFront origin failover: ${n} OriginGroups.Quantity is ${c.Quantity} but it lists ${u.length} group(s).`);let d=new Set;for(let p of u){let g=oe(p.Id);if(p.Id===void 0||p.Id==="")throw Error(`CloudFront origin failover: ${n} has an origin group without an Id.`);let y=`${n} origin group "${g??"(intrinsic id)"}"`;if(g){if(d.has(g))throw Error(`CloudFront origin failover: ${n} declares origin group "${g}" twice.`);if(i.has(g))throw Error(`CloudFront origin failover: ${y} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);d.add(g)}let f=p.Members,h=Ue(f);if(h.length!==2||f?.Quantity!==void 0&&f.Quantity!==h.length)throw Error(`CloudFront origin failover: ${y} must have exactly 2 members (a primary and a secondary), it has ${h.length}${f?.Quantity!==void 0&&f.Quantity!==h.length?` with Quantity ${f.Quantity}`:""}.`);let S=h.map((P)=>oe(P.OriginId));for(let P of S)if(P&&!i.has(P)&&!a)throw Error(`CloudFront origin failover: ${y} lists member "${P}", which is not an origin of this distribution. Origins: ${[...i].join(", ")||"(none)"}.`);if(S[0]&&S[0]===S[1])throw Error(`CloudFront origin failover: ${y} lists "${S[0]}" as both primary and secondary.`);let A=p.FailoverCriteria?.StatusCodes,R=Ue(A);if(ns(R),A?.Quantity!==void 0&&A.Quantity!==R.length)throw Error(`CloudFront origin failover: ${y} FailoverCriteria.StatusCodes.Quantity is ${A.Quantity} but it lists ${R.length} code(s).`);if(on(p.SelectionCriteria,y),p.SelectionCriteria==="media-quality-based")for(let P of S){let C=P?oe(s.get(P)):void 0;if(C&&!Jr.test(C))throw Error(`CloudFront origin failover: ${y} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${P}" is ${C}. Use 'default'.`)}}let m=[];if(e.DefaultCacheBehavior)m.push({behavior:e.DefaultCacheBehavior,name:"the default cache behavior"});for(let p of Ue(e.CacheBehaviors))m.push({behavior:p,name:`the cache behavior for ${JSON.stringify(p.PathPattern)}`});for(let{behavior:p,name:g}of m){let y=oe(p.TargetOriginId);if(!y)continue;if(d.has(y))Rn(p.AllowedMethods??["GET","HEAD"],`${g} of ${n} (origin group "${y}")`);else if(!i.has(y)&&!a&&u.every((f)=>oe(f.Id)!==void 0))throw Error(`CloudFront: ${g} of ${n} targets "${y}", which is neither an origin nor an origin group of this distribution.`)}}class qe{static createDistribution(e){let{slug:n,environment:r,origin:i,customDomain:s,certificateArn:a,errorPages:c,cachePolicy:u,edgeFunctions:d,http3:m=!1,comment:p,failoverOrigin:g}=e,y=l({slug:n,environment:r,resourceType:"cdn"}),f=o(y),h={Id:"DefaultOrigin",DomainName:i.domainName,OriginPath:i.originPath||"",...ct(i,"the CDN origin")},S;if(i.type==="s3"){let R=`${f}OAC`;S={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${y}-oac`,Description:`Origin Access Control for ${y}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},h.OriginAccessControlId=v.Ref(R)}else if(i.type==="alb"||i.type==="custom")h.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let A={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:p||`CDN for ${y}`,DefaultRootObject:"index.html",Origins:[h],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:m?"http2and3":"http2"}}};if(s&&a)A.Properties.DistributionConfig.Aliases=[s],A.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:a,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(c&&c.length>0)A.Properties.DistributionConfig.CustomErrorResponses=c.map((R)=>({ErrorCode:R.errorCode,ResponseCode:R.responseCode,ResponsePagePath:R.responsePagePath}));if(d&&d.length>0)A.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=d.map((R)=>({EventType:R.event,LambdaFunctionARN:R.functionArn}));if(g)qe.addOriginFailover(A,g);return{distribution:A,originAccessControl:S,logicalId:f}}static addOriginFailover(e,n){let r=e.Properties.DistributionConfig,i=r.DefaultCacheBehavior,s=i.TargetOriginId,a=n.id??"FailoverOrigin";if(r.OriginGroups&&r.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(Rn(i.AllowedMethods??["GET","HEAD"],"the default cache behavior"),r.Origins.some((p)=>p.Id===a))throw Error(`CloudFront origin failover: an origin with id "${a}" already exists`);let c=Da({primaryOriginId:s,secondaryOriginId:a,statusCodes:n.statusCodes,selectionCriteria:n.selectionCriteria}),u=n.type??(zi(n.domainName)?"s3":"custom"),d={Id:a,DomainName:n.domainName,OriginPath:n.originPath||"",...ct(n,"the failover origin")},m=ct(n.primary,"the primary origin");if(Object.keys(m).length>0){let p=r.Origins.find((g)=>g.Id===s);if(p)Object.assign(p,m)}if(u==="s3"){let p=r.Origins.find((g)=>g.Id===s);if(d.S3OriginConfig={OriginAccessIdentity:""},p?.OriginAccessControlId)d.OriginAccessControlId=p.OriginAccessControlId}else d.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return r.Origins.push(d),r.OriginGroups={Quantity:1,Items:[c]},i.TargetOriginId=c.Id,In(r),e}static setCustomDomain(e,n,r){return e.Properties.DistributionConfig.Aliases=[n],e.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:r,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},e}static setErrorPages(e,n){return e.Properties.DistributionConfig.CustomErrorResponses=n.map((r)=>({ErrorCode:r.errorCode,ResponseCode:r.responseCode,ResponsePagePath:r.responsePagePath})),e}static enableHttp3(e){return e.Properties.DistributionConfig.HttpVersion="http2and3",e}static addEdgeFunction(e,n,r){if(!e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return e.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:n,LambdaFunctionARN:r}),e}static setCachePolicy(e,n){return e.Properties.DistributionConfig.Comment=`${e.Properties.DistributionConfig.Comment||""} (TTL: ${n.default||86400}s)`,e}static createSpaDistribution(e){return qe.createDistribution({...e,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(e){let{slug:n,environment:r}=e,i=l({slug:n,environment:r,resourceType:"edge-docs"}),s=o(i),a=o(`${i}-role`),c=o(`${i}-version`),u={Type:"AWS::IAM::Role",Properties:{RoleName:`${i}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","edgelambda.amazonaws.com"]},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}},d=`
|
|
95
95
|
'use strict';
|
|
96
96
|
|
|
97
97
|
exports.handler = async (event) => {
|
|
@@ -124,7 +124,7 @@ exports.handler = async (event) => {
|
|
|
124
124
|
|
|
125
125
|
return request;
|
|
126
126
|
};
|
|
127
|
-
`.trim();return{lambdaFunction:{Type:"AWS::Lambda::Function",Properties:{FunctionName:i,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:v.GetAtt(a,"Arn"),Code:{ZipFile:d},MemorySize:128,Timeout:5}},role:u,functionLogicalId:s,roleLogicalId:a,versionLogicalId:c}}static createDocsDistribution(e){let{slug:n,environment:r,origin:i,customDomain:s,certificateArn:a,lambdaEdgeFunctionArn:c}=e,u=
|
|
127
|
+
`.trim();return{lambdaFunction:{Type:"AWS::Lambda::Function",Properties:{FunctionName:i,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:v.GetAtt(a,"Arn"),Code:{ZipFile:d},MemorySize:128,Timeout:5}},role:u,functionLogicalId:s,roleLogicalId:a,versionLogicalId:c}}static createDocsDistribution(e){let{slug:n,environment:r,origin:i,customDomain:s,certificateArn:a,lambdaEdgeFunctionArn:c}=e,u=qe.createDistribution({slug:n,environment:r,origin:i,customDomain:s,certificateArn:a,comment:`Docs CDN for ${n}`,errorPages:[{errorCode:404,responseCode:404,responsePagePath:"/404.html"},{errorCode:403,responseCode:403,responsePagePath:"/404.html"}]});if(c)qe.addEdgeFunction(u.distribution,"origin-request",c);return u.distribution.Properties.DistributionConfig.DefaultCacheBehavior.DefaultTTL=86400,u.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MaxTTL=604800,u.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MinTTL=0,u}static createApiDistribution(e){let{slug:n,environment:r,albDomainName:i,customDomain:s,certificateArn:a,pathPattern:c="/api/*",forwardHeaders:u=["Host","Origin","Authorization","Content-Type","Accept"],forwardCookies:d="all",whitelistedCookies:m,customOriginHeaders:p={}}=e,g=l({slug:n,environment:r,resourceType:"cdn-api"}),y=o(g),f=Object.entries(p).map(([R,P])=>({HeaderName:R,HeaderValue:P})),h={Id:"ALBOrigin",DomainName:i,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(f.length>0)h.OriginCustomHeaders=f;let S={Forward:d};if(d==="whitelist"&&m)S.WhitelistedNames=m;let A={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`API CDN for ${g}`,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:u,Cookies:S}},PriceClass:"PriceClass_100",HttpVersion:"http2"}}};if(s&&a)A.Properties.DistributionConfig.Aliases=[s],A.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:a,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:A,logicalId:y}}static createMultiOriginDistribution(e){let{slug:n,environment:r,s3BucketDomainName:i,albDomainName:s,apiPathPattern:a="/api/*",customDomain:c,certificateArn:u,customOriginHeaders:d={}}=e,m=l({slug:n,environment:r,resourceType:"cdn"}),p=o(m),g=`${p}OAC`,y={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${m}-oac`,Description:`Origin Access Control for ${m}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},f=Object.entries(d).map(([R,P])=>({HeaderName:R,HeaderValue:P})),h={Id:"S3Origin",DomainName:i,OriginAccessControlId:v.Ref(g)},S={Id:"ALBOrigin",DomainName:s,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(f.length>0)S.OriginCustomHeaders=f;let A={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`Multi-origin CDN for ${m}`,DefaultRootObject:"index.html",Origins:[h,S],DefaultCacheBehavior:{TargetOriginId:"S3Origin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},CacheBehaviors:[{PathPattern:a,TargetOriginId:"ALBOrigin",ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:0,MaxTTL:0,MinTTL:0,ForwardedValues:{QueryString:!0,Headers:["Host","Origin","Authorization","Content-Type","Accept"],Cookies:{Forward:"all"}}}],PriceClass:"PriceClass_100",HttpVersion:"http2",CustomErrorResponses:[{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html"},{ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html"}]}}};if(c&&u)A.Properties.DistributionConfig.Aliases=[c],A.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:u,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:A,originAccessControl:y,logicalId:p,oacLogicalId:g}}static addAlbOrigin(e,n){let{originId:r,domainName:i,pathPattern:s,customHeaders:a={},forwardHeaders:c=["Host","Origin","Authorization","Content-Type","Accept"],cacheTtl:u={default:0,max:0,min:0}}=n,d=Object.entries(a).map(([p,g])=>({HeaderName:p,HeaderValue:g})),m={Id:r,DomainName:i,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(d.length>0)m.OriginCustomHeaders=d;if(!e.Properties.DistributionConfig.Origins)e.Properties.DistributionConfig.Origins=[];if(e.Properties.DistributionConfig.Origins.push(m),!e.Properties.DistributionConfig.CacheBehaviors)e.Properties.DistributionConfig.CacheBehaviors=[];return e.Properties.DistributionConfig.CacheBehaviors.push({PathPattern:s,TargetOriginId:r,ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:u.default,MaxTTL:u.max,MinTTL:u.min,ForwardedValues:{QueryString:!0,Headers:c,Cookies:{Forward:"all"}}}),e}static addOriginHeader(e,n,r,i){let s=e.Properties.DistributionConfig.Origins?.find((a)=>a.Id===n);if(s){if(!s.OriginCustomHeaders)s.OriginCustomHeaders=[];s.OriginCustomHeaders.push({HeaderName:r,HeaderValue:i})}return e}static EdgeFunctionTemplates={docsOriginRequest:`
|
|
128
128
|
'use strict';
|
|
129
129
|
exports.handler = async (event) => {
|
|
130
130
|
const request = event.Records[0].cf.request;
|
|
@@ -197,7 +197,7 @@ exports.handler = async (event) => {
|
|
|
197
197
|
|
|
198
198
|
return request;
|
|
199
199
|
};
|
|
200
|
-
`.trim()};static Config={ttl:(e)=>{let{min:n=0,max:r=86400,default:i=86400}=e;return{MinTTL:n,MaxTTL:r,DefaultTTL:i}},cookies:(e,n)=>{let r={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&n)r.WhitelistedNames=n;return r},allowedMethods:(e)=>{let n={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return n[e]||n.GET_HEAD},cachedMethods:(e)=>{let n={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return n[e]||n.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:n={min:0,max:86400,default:86400},cookies:r="none",allowedCookies:i,allowedMethods:s="GET_HEAD",cachedMethods:a="GET_HEAD",compress:c=!0,forwardQueryString:u=!0,forwardHeaders:d=[]}=e;return{MinTTL:n.min,MaxTTL:n.max,DefaultTTL:n.default,Compress:c,AllowedMethods:Ge.Config.allowedMethods(s),CachedMethods:Ge.Config.cachedMethods(a),ForwardedValues:{QueryString:u,Headers:d,Cookies:Ge.Config.cookies(r,i)}}}};static applyConfig(e,n){let r=e.Properties.DistributionConfig.DefaultCacheBehavior;if(n.ttl)r.MinTTL=n.ttl.min,r.MaxTTL=n.ttl.max,r.DefaultTTL=n.ttl.default;if(n.compress!==void 0)r.Compress=n.compress;if(n.allowedMethods)r.AllowedMethods=Ge.Config.allowedMethods(n.allowedMethods);if(n.cachedMethods)r.CachedMethods=Ge.Config.cachedMethods(n.cachedMethods);if(n.cookies){if(!r.ForwardedValues)r.ForwardedValues={QueryString:!0};r.ForwardedValues.Cookies=Ge.Config.cookies(n.cookies,n.allowedCookies)}return e}}var pu=[403,404,500,502,503,504],es="TsCloud::StorageFailover",ts="AllowCloudFrontFailoverRead",wr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,Ir=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function Ta(e){let{failover:n,primaryBucket:r,primaryRegion:i}=e,s=e.where??"storage failover";if(!n||typeof n!=="object")throw Error(`${s}.failover must be an object such as { region: 'us-west-2' }.`);if(!n.region||!wr.test(n.region))throw Error(`${s}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(n.region)}.`);if(n.region===i)throw Error(`${s}.failover.region is ${n.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let a=n.bucket??`${r}-${n.region}`;if(!Ir.test(a)||a.includes("..")){let c=n.bucket===void 0&&a.length>63?` The default name (<primary bucket>-<region>) is ${a.length} characters; S3 allows 63. Set ${s}.failover.bucket.`:"";throw Error(`${s}.failover: "${a}" is not a valid S3 bucket name.${c}`)}if(a===r)throw Error(`${s}.failover.bucket must differ from the primary bucket "${r}".`);return{replicaBucket:a,replicaRegion:n.region,replicate:n.replicate!==!1,statusCodes:Yo(n.statusCodes??pu),primaryConnection:st(n,`${s}.failover`)}}function Ea(e,n){return`${e}.s3.${n}.amazonaws.com`}function wa(e){let n=`arn:aws:s3:::${e.primaryBucket}`,r=`arn:aws:s3:::${e.replicaBucket}`;return{Type:"AWS::IAM::Role",Properties:{...e.roleName?{RoleName:e.roleName}:{},AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"s3.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"failover-replication",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetReplicationConfiguration","s3:ListBucket"],Resource:n},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${n}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${r}/*`}]}}]}}}function Aa(e){return{Role:e.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${e.replicaBucket}`}}]}}function Ra(e){return{Sid:ts,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function Ia(e){let r=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[es];return Array.isArray(r)?r:[]}class Ae{static createHostedZone(e){let{domain:n,slug:r,environment:i,comment:s}=e,a=l({slug:r,environment:i,resourceType:"hostedzone"}),c=o(`${a}-${n.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:n,HostedZoneConfig:{Comment:s||`Hosted zone for ${n}`}}},logicalId:c}}static createRecord(e){let{hostedZoneId:n,hostedZoneName:r,name:i,type:s,ttl:a,values:c,aliasTarget:u}=e,d=o(`record-${i.replace(/\./g,"")}-${s}`),m={Type:"AWS::Route53::RecordSet",Properties:{Name:i,Type:s}};if(n)m.Properties.HostedZoneId=n;else if(r)m.Properties.HostedZoneName=r;if(u)m.Properties.AliasTarget={DNSName:u.dnsName,HostedZoneId:u.hostedZoneId,EvaluateTargetHealth:u.evaluateTargetHealth??!1};else m.Properties.TTL=a||300,m.Properties.ResourceRecords=c||[];return{record:m,logicalId:d}}static createCloudFrontAlias(e,n,r){return Ae.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,n,r,i){return Ae.createRecord({hostedZoneId:i,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:r,evaluateTargetHealth:!0}})}static createCname(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"CNAME",ttl:i,values:[n]})}static createWwwRedirect(e,n){return Ae.createRecord({hostedZoneId:n,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"MX",ttl:i,values:n.map((s)=>`${s.priority} ${s.server}`)})}static createTxtRecord(e,n,r,i=300){return Ae.createRecord({hostedZoneId:r,name:e,type:"TXT",ttl:i,values:[`"${n}"`]})}static createSpfRecord(e,n,r){return Ae.createTxtRecord(e,n,r)}static createDmarcRecord(e,n,r,i){let s=`v=DMARC1; p=${n}; rua=mailto:${r}`;return Ae.createTxtRecord(`_dmarc.${e}`,s,i)}static createS3WebsiteAlias(e,n,r,i){return Ae.createRecord({hostedZoneId:i,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:r,evaluateTargetHealth:!1}})}static S3WebsiteHostedZoneIds={"us-east-1":"Z3AQBSTGFYJSTF","us-east-2":"Z2O1EMRO9K5GLX","us-west-1":"Z2F56UZL2M1ACD","us-west-2":"Z3BJ6K6RIION7M","af-south-1":"Z83WF9RJE8B12","ap-east-1":"ZNB98KWMFR0R6","ap-south-1":"Z11RGJOFQNVJUP","ap-south-2":"Z02976202B4EZMXIPMXF7","ap-northeast-1":"Z2M4EHUR26P7ZW","ap-northeast-2":"Z3W03O7B5YMIYP","ap-northeast-3":"Z2YQB5RD63NC85","ap-southeast-1":"Z3O0J2DXBE1FTB","ap-southeast-2":"Z1WCIBER6CPFUU","ap-southeast-3":"Z01613992JD795ZI93075","ca-central-1":"Z1QDHH18159H29","eu-central-1":"Z21DNDUVLTQW6Q","eu-central-2":"Z030506016YDQGETNASS","eu-west-1":"Z1BKCTXD74EZPE","eu-west-2":"Z3GKZC51ZF0DB4","eu-west-3":"Z3R1K369G5AVDG","eu-north-1":"Z3BAZG2TWCNX0D","eu-south-1":"Z30OZKI7KPW7MI","eu-south-2":"Z0081959F7139GRJC19J","me-south-1":"Z1MPMWCPA7YB62","me-central-1":"Z06143092I8HRBER9VXCO","sa-east-1":"Z7KQH4QJS55SO"};static getS3WebsiteEndpoint(e,n){return`${e}.s3-website-${n}.amazonaws.com`}static createStoreRecord(e,n,r){return Ae.createCname(`store.${e}`,n,r)}static createApiRecord(e,n,r){return Ae.createCname(`api.${e}`,n,r)}static createDocsRecord(e,n,r){return Ae.createCname(`docs.${e}`,n,r)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class j{static createCertificate(e){let{domain:n,subdomains:r=[],slug:i,environment:s,validationMethod:a="DNS",hostedZoneId:c}=e,u=l({slug:i,environment:s,resourceType:"acm"}),d=o(`${u}-${n.replace(/\./g,"")}`),m=[n];for(let g of r)if(g==="*")m.push(`*.${n}`);else m.push(`${g}.${n}`);let p={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n,SubjectAlternativeNames:m,ValidationMethod:a}};if(a==="DNS"&&c)p.Properties.DomainValidationOptions=m.map((g)=>({DomainName:g,HostedZoneId:c}));return{certificate:p,logicalId:d}}static createKmsKey(e){let{description:n,slug:r,environment:i,enableRotation:s=!0,multiRegion:a=!1}=e,c=l({slug:r,environment:i,resourceType:"kms"}),u=o(c),d={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:v.Sub("arn:aws:iam::${AWS::AccountId}:root")},Action:"kms:*",Resource:"*"},{Sid:"Allow services to use the key",Effect:"Allow",Principal:{Service:["s3.amazonaws.com","cloudfront.amazonaws.com","logs.amazonaws.com","secretsmanager.amazonaws.com"]},Action:["kms:Decrypt","kms:GenerateDataKey"],Resource:"*"}]},m={Type:"AWS::KMS::Key",Properties:{Description:n,Enabled:!0,EnableKeyRotation:s,KeyPolicy:d,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:a}},p=o(`${c}-alias`),g={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${r}-${i}`,TargetKeyId:v.Ref(u)}};return{key:m,alias:g,logicalId:u,aliasId:p}}static createFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",defaultAction:s="allow"}=e,a=l({slug:n,environment:r,resourceType:"waf"}),c=o(a);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:a,Scope:i,DefaultAction:s==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${n} ${r}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-metric`}}},logicalId:c}}static setRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:n.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static blockCountries(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{GeoMatchStatement:{CountryCodes:n.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static blockIpAddresses(e,n,r,i){let s=l({slug:r,environment:i,resourceType:"ipset"}),a=o(`${s}-${n.name}`),c={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${s}-${n.name}`,Scope:e.Properties.Scope,IPAddressVersion:n.ipVersion||"IPV4",Addresses:n.ipAddresses,Description:`Blocked IPs for ${n.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{IPSetReferenceStatement:{Arn:v.GetAtt(a,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),{webAcl:e,ipSet:c,ipSetLogicalId:a}}static addManagedRules(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r={ManagedRuleGroupStatement:{VendorName:n.vendorName,Name:n.ruleName}};if(n.excludedRules&&n.excludedRules.length>0)r.ManagedRuleGroupStatement.ExcludedRules=n.excludedRules.map((i)=>({Name:i}));return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:r,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.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,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r=n.paths.map((i)=>({SearchString:i,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:n.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:r.map((i)=>({ByteMatchStatement:i}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static setHeaderRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r={RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:n.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(n.headerValue)r.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:n.headerValue,FieldToMatch:{SingleHeader:{Name:n.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:r,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static protectLoginEndpoint(e,n){let{loginPaths:r,priority:i,requestsPerMinute:s=10}=n;return j.setPathRateLimit(e,{name:"LoginRateLimit",priority:i,requestsPerWindow:s*5,paths:r}),e}static protectApiEndpoints(e,n){let{apiPaths:r,priority:i,requestsPerMinute:s=100}=n;return j.setPathRateLimit(e,{name:"ApiRateLimit",priority:i,requestsPerWindow:s*5,paths:r}),e}static createProtectedFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",enableBotControl:s=!1,enableRateLimiting:a=!0,rateLimitPerMinute:c=2000}=e,{webAcl:u,logicalId:d}=j.createFirewall({slug:n,environment:r,scope:i,defaultAction:"allow"}),m=0;if(u=j.addManagedRules(u,{name:"AWSIPReputationList",priority:m++,...j.ManagedRuleGroups.AmazonIpReputation}),u=j.addManagedRules(u,{name:"AWSAnonymousIPList",priority:m++,...j.ManagedRuleGroups.AnonymousIpList}),u=j.addManagedRules(u,{name:"AWSCoreRuleSet",priority:m++,...j.ManagedRuleGroups.CoreRuleSet}),u=j.addManagedRules(u,{name:"AWSKnownBadInputs",priority:m++,...j.ManagedRuleGroups.KnownBadInputs}),u=j.addManagedRules(u,{name:"AWSSQLi",priority:m++,...j.ManagedRuleGroups.SqlDatabase}),s)u=j.addManagedRules(u,{name:"AWSBotControl",priority:m++,...j.ManagedRuleGroups.BotControl});if(a)u=j.setRateLimit(u,{name:"GlobalRateLimit",priority:m++,requestsPerWindow:c*5});return{webAcl:u,logicalId:d}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}function mu(e){let n=e.split(".")[0]??"";return n==="a1"||/^[a-z]+\d+g[a-z]*$/.test(n)}function gu(e="t3.micro"){return`/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${mu(e)?"arm64":"x86_64"}`}function pl(e="t3.micro"){return`{{resolve:ssm:${gu(e)}}}`}class b{static createServer(e){let{slug:n,environment:r,instanceType:i="t3.micro",imageId:s=pl(i),keyName:a,securityGroupIds:c,subnetId:u,userData:d,volumeSize:m=20,volumeType:p="gp3",encrypted:g=!0}=e,y=l({slug:n,environment:r,resourceType:"ec2"}),f=o(y),h={Type:"AWS::EC2::Instance",Properties:{ImageId:s,InstanceType:i,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(a)h.Properties.KeyName=a;if(c)h.Properties.SecurityGroupIds=c;if(u)h.Properties.SubnetId=u;if(d)h.Properties.UserData=v.Base64(d);return h.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:g,DeleteOnTermination:!0}}],{instance:h,logicalId:f}}static createSecurityGroup(e){let{slug:n,environment:r,vpcId:i,description:s,ingress:a=[],egress:c=[]}=e,u=l({slug:n,environment:r,resourceType:"sg"}),d=o(u),m={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:s||`Security group for ${n} ${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(i)m.Properties.VpcId=i;if(a.length>0)m.Properties.SecurityGroupIngress=a.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,SourceSecurityGroupId:p.sourceSecurityGroupId}));if(c.length>0)m.Properties.SecurityGroupEgress=c.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,DestinationSecurityGroupId:p.sourceSecurityGroupId}));return{securityGroup:m,logicalId:d}}static createWebServerSecurityGroup(e,n,r){return b.createSecurityGroup({slug:e,environment:n,vpcId:r,description:"Security group for web servers - HTTP, HTTPS, SSH",ingress:[{protocol:"tcp",fromPort:80,toPort:80,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:443,toPort:443,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:22,toPort:22,cidr:"0.0.0.0/0"}],egress:[{protocol:"-1",fromPort:0,toPort:0,cidr:"0.0.0.0/0"}]})}static createLoadBalancer(e){let{slug:n,environment:r,scheme:i="internet-facing",subnets:s,securityGroups:a,type:c="application"}=e,u=l({slug:n,environment:r,resourceType:"alb"}),d=o(u),m={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:u,Scheme:i,Type:c,Subnets:s,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(a)m.Properties.SecurityGroups=a;return{loadBalancer:m,logicalId:d}}static createTargetGroup(e){let{slug:n,environment:r,port:i,protocol:s="HTTP",vpcId:a,targetType:c="ip",healthCheckPath:u="/",healthCheckInterval:d=30,healthCheckTimeout:m=5,healthyThreshold:p=2,unhealthyThreshold:g=3}=e,y=l({slug:n,environment:r,resourceType:"tg"}),f=o(y);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:y,Port:i,Protocol:s,VpcId:a,TargetType:c,HealthCheckEnabled:!0,HealthCheckProtocol:s,HealthCheckPath:u,HealthCheckIntervalSeconds:d,HealthCheckTimeoutSeconds:m,HealthyThresholdCount:p,UnhealthyThresholdCount:g,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}},logicalId:f}}static createListener(e,n){let{port:r,protocol:i="HTTP",certificateArn:s,defaultTargetGroupArn:a}=n,c=o(`listener-${e}-${r}`),u={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:v.Ref(e),Port:r,Protocol:i,DefaultActions:[{Type:"forward",TargetGroupArn:a}]}};if(i==="HTTPS"&&s)u.Properties.Certificates=[{CertificateArn:s}],u.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:u,logicalId:c}}static createEcsCluster(e,n){let r=l({slug:e,environment:n,resourceType:"ecs-cluster"}),i=o(r);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:r,Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static createFargateService(e){let{slug:n,environment:r,image:i,cpu:s="256",memory:a="512",desiredCount:c=1,containerPort:u=8080,environmentVariables:d={},secrets:m=[],healthCheck:p,logGroup:g,subnets:y,securityGroups:f,targetGroupArn:h}=e,{cluster:S,logicalId:A}=b.createEcsCluster(n,r),R=l({slug:n,environment:r,resourceType:"fargate"}),P=o(`${R}-execution-role`),C={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]}},E=o(`${R}-task-role`),D={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},x=o(`${R}-task`),L={Type:"AWS::ECS::TaskDefinition",Properties:{Family:R,TaskRoleArn:v.GetAtt(E,"Arn"),ExecutionRoleArn:v.GetAtt(P,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:s,Memory:a,ContainerDefinitions:[{Name:n,Image:i,Essential:!0,PortMappings:[{ContainerPort:u,Protocol:"tcp"}],Environment:Object.entries(d).map(([F,V])=>({Name:F,Value:V})),Secrets:m.map((F)=>({Name:F.name,ValueFrom:F.valueFrom}))}],Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:r}]}};if(p)L.Properties.ContainerDefinitions[0].HealthCheck={Command:p.command,Interval:p.interval||30,Timeout:p.timeout||5,Retries:p.retries||3,StartPeriod:60};if(g)L.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":g,"awslogs-region":v.Ref("AWS::Region"),"awslogs-stream-prefix":n}};let B=o(`${R}-service`),O={Type:"AWS::ECS::Service",Properties:{ServiceName:R,Cluster:v.Ref(A),TaskDefinition:v.Ref(x),DesiredCount:c,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:y,SecurityGroups:f,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:r}]}};if(h)O.Properties.LoadBalancers=[{TargetGroupArn:h,ContainerName:n,ContainerPort:u}];return{cluster:S,taskDefinition:L,service:O,taskRole:D,executionRole:C,clusterLogicalId:A,taskDefinitionLogicalId:x,serviceLogicalId:B,taskRoleLogicalId:E,executionRoleLogicalId:P}}static createLambdaFunction(e){let{slug:n,environment:r,runtime:i,handler:s,code:a,timeout:c=30,memorySize:u=128,environmentVariables:d={},vpcConfig:m}=e,p=l({slug:n,environment:r,resourceType:"lambda"}),g=o(p),y=o(`${p}-role`),f={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}};if(m)f.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let h={Type:"AWS::Lambda::Function",Properties:{FunctionName:p,Runtime:i,Role:v.GetAtt(y,"Arn"),Handler:s,Code:{...a.s3Bucket&&{S3Bucket:a.s3Bucket},...a.s3Key&&{S3Key:a.s3Key},...a.zipFile&&{ZipFile:a.zipFile}},Timeout:c,MemorySize:u,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r}]}};if(Object.keys(d).length>0)h.Properties.Environment={Variables:d};if(m)h.Properties.VpcConfig={SecurityGroupIds:m.securityGroupIds,SubnetIds:m.subnetIds};return{lambdaFunction:h,role:f,logicalId:g,roleLogicalId:y}}static generateNodeServerUserData(e={}){let{nodeVersion:n="20",appRepo:r,environment:i={}}=e,s=Object.entries(i).map(([a,c])=>`echo "export ${a}='${c}'" >> /etc/environment`).join(`
|
|
200
|
+
`.trim()};static Config={ttl:(e)=>{let{min:n=0,max:r=86400,default:i=86400}=e;return{MinTTL:n,MaxTTL:r,DefaultTTL:i}},cookies:(e,n)=>{let r={Forward:e==="allowList"?"whitelist":e};if(e==="allowList"&&n)r.WhitelistedNames=n;return r},allowedMethods:(e)=>{let n={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return n[e]||n.GET_HEAD},cachedMethods:(e)=>{let n={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return n[e]||n.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:n={min:0,max:86400,default:86400},cookies:r="none",allowedCookies:i,allowedMethods:s="GET_HEAD",cachedMethods:a="GET_HEAD",compress:c=!0,forwardQueryString:u=!0,forwardHeaders:d=[]}=e;return{MinTTL:n.min,MaxTTL:n.max,DefaultTTL:n.default,Compress:c,AllowedMethods:qe.Config.allowedMethods(s),CachedMethods:qe.Config.cachedMethods(a),ForwardedValues:{QueryString:u,Headers:d,Cookies:qe.Config.cookies(r,i)}}}};static applyConfig(e,n){let r=e.Properties.DistributionConfig.DefaultCacheBehavior;if(n.ttl)r.MinTTL=n.ttl.min,r.MaxTTL=n.ttl.max,r.DefaultTTL=n.ttl.default;if(n.compress!==void 0)r.Compress=n.compress;if(n.allowedMethods)r.AllowedMethods=qe.Config.allowedMethods(n.allowedMethods);if(n.cachedMethods)r.CachedMethods=qe.Config.cachedMethods(n.cachedMethods);if(n.cookies){if(!r.ForwardedValues)r.ForwardedValues={QueryString:!0};r.ForwardedValues.Cookies=qe.Config.cookies(n.cookies,n.allowedCookies)}return e}}var Tu=[403,404,500,502,503,504],os="TsCloud::StorageFailover",ss="AllowCloudFrontFailoverRead",Yr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,Zr=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function ka(e){let{failover:n,primaryBucket:r,primaryRegion:i}=e,s=e.where??"storage failover";if(!n||typeof n!=="object")throw Error(`${s}.failover must be an object such as { region: 'us-west-2' }.`);if(!n.region||!Yr.test(n.region))throw Error(`${s}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(n.region)}.`);if(n.region===i)throw Error(`${s}.failover.region is ${n.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let a=n.bucket??`${r}-${n.region}`;if(!Zr.test(a)||a.includes("..")){let c=n.bucket===void 0&&a.length>63?` The default name (<primary bucket>-<region>) is ${a.length} characters; S3 allows 63. Set ${s}.failover.bucket.`:"";throw Error(`${s}.failover: "${a}" is not a valid S3 bucket name.${c}`)}if(a===r)throw Error(`${s}.failover.bucket must differ from the primary bucket "${r}".`);return{replicaBucket:a,replicaRegion:n.region,replicate:n.replicate!==!1,statusCodes:ns(n.statusCodes??Tu),primaryConnection:ct(n,`${s}.failover`)}}function Na(e,n){return`${e}.s3.${n}.amazonaws.com`}function xa(e){let n=`arn:aws:s3:::${e.primaryBucket}`,r=`arn:aws:s3:::${e.replicaBucket}`;return{Type:"AWS::IAM::Role",Properties:{...e.roleName?{RoleName:e.roleName}:{},AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"s3.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"failover-replication",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetReplicationConfiguration","s3:ListBucket"],Resource:n},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${n}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${r}/*`}]}}]}}}function _a(e){return{Role:e.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${e.replicaBucket}`}}]}}function Oa(e){return{Sid:ss,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function $a(e){let r=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[os];return Array.isArray(r)?r:[]}class Re{static createHostedZone(e){let{domain:n,slug:r,environment:i,comment:s}=e,a=l({slug:r,environment:i,resourceType:"hostedzone"}),c=o(`${a}-${n.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:n,HostedZoneConfig:{Comment:s||`Hosted zone for ${n}`}}},logicalId:c}}static createRecord(e){let{hostedZoneId:n,hostedZoneName:r,name:i,type:s,ttl:a,values:c,aliasTarget:u}=e,d=o(`record-${i.replace(/\./g,"")}-${s}`),m={Type:"AWS::Route53::RecordSet",Properties:{Name:i,Type:s}};if(n)m.Properties.HostedZoneId=n;else if(r)m.Properties.HostedZoneName=r;if(u)m.Properties.AliasTarget={DNSName:u.dnsName,HostedZoneId:u.hostedZoneId,EvaluateTargetHealth:u.evaluateTargetHealth??!1};else m.Properties.TTL=a||300,m.Properties.ResourceRecords=c||[];return{record:m,logicalId:d}}static createCloudFrontAlias(e,n,r){return Re.createRecord({hostedZoneId:r,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(e,n,r,i){return Re.createRecord({hostedZoneId:i,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:r,evaluateTargetHealth:!0}})}static createCname(e,n,r,i=300){return Re.createRecord({hostedZoneId:r,name:e,type:"CNAME",ttl:i,values:[n]})}static createWwwRedirect(e,n){return Re.createRecord({hostedZoneId:n,name:`www.${e}`,type:"CNAME",ttl:300,values:[e]})}static createMxRecords(e,n,r,i=300){return Re.createRecord({hostedZoneId:r,name:e,type:"MX",ttl:i,values:n.map((s)=>`${s.priority} ${s.server}`)})}static createTxtRecord(e,n,r,i=300){return Re.createRecord({hostedZoneId:r,name:e,type:"TXT",ttl:i,values:[`"${n}"`]})}static createSpfRecord(e,n,r){return Re.createTxtRecord(e,n,r)}static createDmarcRecord(e,n,r,i){let s=`v=DMARC1; p=${n}; rua=mailto:${r}`;return Re.createTxtRecord(`_dmarc.${e}`,s,i)}static createS3WebsiteAlias(e,n,r,i){return Re.createRecord({hostedZoneId:i,name:e,type:"A",aliasTarget:{dnsName:n,hostedZoneId:r,evaluateTargetHealth:!1}})}static S3WebsiteHostedZoneIds={"us-east-1":"Z3AQBSTGFYJSTF","us-east-2":"Z2O1EMRO9K5GLX","us-west-1":"Z2F56UZL2M1ACD","us-west-2":"Z3BJ6K6RIION7M","af-south-1":"Z83WF9RJE8B12","ap-east-1":"ZNB98KWMFR0R6","ap-south-1":"Z11RGJOFQNVJUP","ap-south-2":"Z02976202B4EZMXIPMXF7","ap-northeast-1":"Z2M4EHUR26P7ZW","ap-northeast-2":"Z3W03O7B5YMIYP","ap-northeast-3":"Z2YQB5RD63NC85","ap-southeast-1":"Z3O0J2DXBE1FTB","ap-southeast-2":"Z1WCIBER6CPFUU","ap-southeast-3":"Z01613992JD795ZI93075","ca-central-1":"Z1QDHH18159H29","eu-central-1":"Z21DNDUVLTQW6Q","eu-central-2":"Z030506016YDQGETNASS","eu-west-1":"Z1BKCTXD74EZPE","eu-west-2":"Z3GKZC51ZF0DB4","eu-west-3":"Z3R1K369G5AVDG","eu-north-1":"Z3BAZG2TWCNX0D","eu-south-1":"Z30OZKI7KPW7MI","eu-south-2":"Z0081959F7139GRJC19J","me-south-1":"Z1MPMWCPA7YB62","me-central-1":"Z06143092I8HRBER9VXCO","sa-east-1":"Z7KQH4QJS55SO"};static getS3WebsiteEndpoint(e,n){return`${e}.s3-website-${n}.amazonaws.com`}static createStoreRecord(e,n,r){return Re.createCname(`store.${e}`,n,r)}static createApiRecord(e,n,r){return Re.createCname(`api.${e}`,n,r)}static createDocsRecord(e,n,r){return Re.createCname(`docs.${e}`,n,r)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class j{static createCertificate(e){let{domain:n,subdomains:r=[],slug:i,environment:s,validationMethod:a="DNS",hostedZoneId:c}=e,u=l({slug:i,environment:s,resourceType:"acm"}),d=o(`${u}-${n.replace(/\./g,"")}`),m=[n];for(let g of r)if(g==="*")m.push(`*.${n}`);else m.push(`${g}.${n}`);let p={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n,SubjectAlternativeNames:m,ValidationMethod:a}};if(a==="DNS"&&c)p.Properties.DomainValidationOptions=m.map((g)=>({DomainName:g,HostedZoneId:c}));return{certificate:p,logicalId:d}}static createKmsKey(e){let{description:n,slug:r,environment:i,enableRotation:s=!0,multiRegion:a=!1}=e,c=l({slug:r,environment:i,resourceType:"kms"}),u=o(c),d={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:v.Sub("arn:aws:iam::${AWS::AccountId}:root")},Action:"kms:*",Resource:"*"},{Sid:"Allow services to use the key",Effect:"Allow",Principal:{Service:["s3.amazonaws.com","cloudfront.amazonaws.com","logs.amazonaws.com","secretsmanager.amazonaws.com"]},Action:["kms:Decrypt","kms:GenerateDataKey"],Resource:"*"}]},m={Type:"AWS::KMS::Key",Properties:{Description:n,Enabled:!0,EnableKeyRotation:s,KeyPolicy:d,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:a}},p=o(`${c}-alias`),g={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${r}-${i}`,TargetKeyId:v.Ref(u)}};return{key:m,alias:g,logicalId:u,aliasId:p}}static createFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",defaultAction:s="allow"}=e,a=l({slug:n,environment:r,resourceType:"waf"}),c=o(a);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:a,Scope:i,DefaultAction:s==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${n} ${r}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-metric`}}},logicalId:c}}static setRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:n.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static blockCountries(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{GeoMatchStatement:{CountryCodes:n.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static blockIpAddresses(e,n,r,i){let s=l({slug:r,environment:i,resourceType:"ipset"}),a=o(`${s}-${n.name}`),c={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${s}-${n.name}`,Scope:e.Properties.Scope,IPAddressVersion:n.ipVersion||"IPV4",Addresses:n.ipAddresses,Description:`Blocked IPs for ${n.name}`}};if(!e.Properties.Rules)e.Properties.Rules=[];return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{IPSetReferenceStatement:{Arn:v.GetAtt(a,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),{webAcl:e,ipSet:c,ipSetLogicalId:a}}static addManagedRules(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r={ManagedRuleGroupStatement:{VendorName:n.vendorName,Name:n.ruleName}};if(n.excludedRules&&n.excludedRules.length>0)r.ManagedRuleGroupStatement.ExcludedRules=n.excludedRules.map((i)=>({Name:i}));return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:r,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.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,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r=n.paths.map((i)=>({SearchString:i,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:{RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:n.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:r.map((i)=>({ByteMatchStatement:i}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static setHeaderRateLimit(e,n){if(!e.Properties.Rules)e.Properties.Rules=[];let r={RateBasedStatement:{Limit:n.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:n.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(n.headerValue)r.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:n.headerValue,FieldToMatch:{SingleHeader:{Name:n.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return e.Properties.Rules.push({Name:n.name,Priority:n.priority,Statement:r,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),e}static protectLoginEndpoint(e,n){let{loginPaths:r,priority:i,requestsPerMinute:s=10}=n;return j.setPathRateLimit(e,{name:"LoginRateLimit",priority:i,requestsPerWindow:s*5,paths:r}),e}static protectApiEndpoints(e,n){let{apiPaths:r,priority:i,requestsPerMinute:s=100}=n;return j.setPathRateLimit(e,{name:"ApiRateLimit",priority:i,requestsPerWindow:s*5,paths:r}),e}static createProtectedFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",enableBotControl:s=!1,enableRateLimiting:a=!0,rateLimitPerMinute:c=2000}=e,{webAcl:u,logicalId:d}=j.createFirewall({slug:n,environment:r,scope:i,defaultAction:"allow"}),m=0;if(u=j.addManagedRules(u,{name:"AWSIPReputationList",priority:m++,...j.ManagedRuleGroups.AmazonIpReputation}),u=j.addManagedRules(u,{name:"AWSAnonymousIPList",priority:m++,...j.ManagedRuleGroups.AnonymousIpList}),u=j.addManagedRules(u,{name:"AWSCoreRuleSet",priority:m++,...j.ManagedRuleGroups.CoreRuleSet}),u=j.addManagedRules(u,{name:"AWSKnownBadInputs",priority:m++,...j.ManagedRuleGroups.KnownBadInputs}),u=j.addManagedRules(u,{name:"AWSSQLi",priority:m++,...j.ManagedRuleGroups.SqlDatabase}),s)u=j.addManagedRules(u,{name:"AWSBotControl",priority:m++,...j.ManagedRuleGroups.BotControl});if(a)u=j.setRateLimit(u,{name:"GlobalRateLimit",priority:m++,requestsPerWindow:c*5});return{webAcl:u,logicalId:d}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}function Eu(e){let n=e.split(".")[0]??"";return n==="a1"||/^[a-z]+\d+g[a-z]*$/.test(n)}function wu(e="t3.micro"){return`/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${Eu(e)?"arm64":"x86_64"}`}function Cl(e="t3.micro"){return`{{resolve:ssm:${wu(e)}}}`}class b{static createServer(e){let{slug:n,environment:r,instanceType:i="t3.micro",imageId:s=Cl(i),keyName:a,securityGroupIds:c,subnetId:u,userData:d,volumeSize:m=20,volumeType:p="gp3",encrypted:g=!0}=e,y=l({slug:n,environment:r,resourceType:"ec2"}),f=o(y),h={Type:"AWS::EC2::Instance",Properties:{ImageId:s,InstanceType:i,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(a)h.Properties.KeyName=a;if(c)h.Properties.SecurityGroupIds=c;if(u)h.Properties.SubnetId=u;if(d)h.Properties.UserData=v.Base64(d);return h.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:m,VolumeType:p,Encrypted:g,DeleteOnTermination:!0}}],{instance:h,logicalId:f}}static createSecurityGroup(e){let{slug:n,environment:r,vpcId:i,description:s,ingress:a=[],egress:c=[]}=e,u=l({slug:n,environment:r,resourceType:"sg"}),d=o(u),m={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:s||`Security group for ${n} ${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(i)m.Properties.VpcId=i;if(a.length>0)m.Properties.SecurityGroupIngress=a.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,SourceSecurityGroupId:p.sourceSecurityGroupId}));if(c.length>0)m.Properties.SecurityGroupEgress=c.map((p)=>({IpProtocol:p.protocol,FromPort:p.fromPort,ToPort:p.toPort,CidrIp:p.cidr,DestinationSecurityGroupId:p.sourceSecurityGroupId}));return{securityGroup:m,logicalId:d}}static createWebServerSecurityGroup(e,n,r){return b.createSecurityGroup({slug:e,environment:n,vpcId:r,description:"Security group for web servers - HTTP, HTTPS, SSH",ingress:[{protocol:"tcp",fromPort:80,toPort:80,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:443,toPort:443,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:22,toPort:22,cidr:"0.0.0.0/0"}],egress:[{protocol:"-1",fromPort:0,toPort:0,cidr:"0.0.0.0/0"}]})}static createLoadBalancer(e){let{slug:n,environment:r,scheme:i="internet-facing",subnets:s,securityGroups:a,type:c="application"}=e,u=l({slug:n,environment:r,resourceType:"alb"}),d=o(u),m={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:u,Scheme:i,Type:c,Subnets:s,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(a)m.Properties.SecurityGroups=a;return{loadBalancer:m,logicalId:d}}static createTargetGroup(e){let{slug:n,environment:r,port:i,protocol:s="HTTP",vpcId:a,targetType:c="ip",healthCheckPath:u="/",healthCheckInterval:d=30,healthCheckTimeout:m=5,healthyThreshold:p=2,unhealthyThreshold:g=3}=e,y=l({slug:n,environment:r,resourceType:"tg"}),f=o(y);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:y,Port:i,Protocol:s,VpcId:a,TargetType:c,HealthCheckEnabled:!0,HealthCheckProtocol:s,HealthCheckPath:u,HealthCheckIntervalSeconds:d,HealthCheckTimeoutSeconds:m,HealthyThresholdCount:p,UnhealthyThresholdCount:g,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}},logicalId:f}}static createListener(e,n){let{port:r,protocol:i="HTTP",certificateArn:s,defaultTargetGroupArn:a}=n,c=o(`listener-${e}-${r}`),u={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:v.Ref(e),Port:r,Protocol:i,DefaultActions:[{Type:"forward",TargetGroupArn:a}]}};if(i==="HTTPS"&&s)u.Properties.Certificates=[{CertificateArn:s}],u.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:u,logicalId:c}}static createEcsCluster(e,n){let r=l({slug:e,environment:n,resourceType:"ecs-cluster"}),i=o(r);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:r,Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static createFargateService(e){let{slug:n,environment:r,image:i,cpu:s="256",memory:a="512",desiredCount:c=1,containerPort:u=8080,environmentVariables:d={},secrets:m=[],healthCheck:p,logGroup:g,subnets:y,securityGroups:f,targetGroupArn:h}=e,{cluster:S,logicalId:A}=b.createEcsCluster(n,r),R=l({slug:n,environment:r,resourceType:"fargate"}),P=o(`${R}-execution-role`),C={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]}},E=o(`${R}-task-role`),D={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},x=o(`${R}-task`),L={Type:"AWS::ECS::TaskDefinition",Properties:{Family:R,TaskRoleArn:v.GetAtt(E,"Arn"),ExecutionRoleArn:v.GetAtt(P,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:s,Memory:a,ContainerDefinitions:[{Name:n,Image:i,Essential:!0,PortMappings:[{ContainerPort:u,Protocol:"tcp"}],Environment:Object.entries(d).map(([F,V])=>({Name:F,Value:V})),Secrets:m.map((F)=>({Name:F.name,ValueFrom:F.valueFrom}))}],Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:r}]}};if(p)L.Properties.ContainerDefinitions[0].HealthCheck={Command:p.command,Interval:p.interval||30,Timeout:p.timeout||5,Retries:p.retries||3,StartPeriod:60};if(g)L.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":g,"awslogs-region":v.Ref("AWS::Region"),"awslogs-stream-prefix":n}};let B=o(`${R}-service`),O={Type:"AWS::ECS::Service",Properties:{ServiceName:R,Cluster:v.Ref(A),TaskDefinition:v.Ref(x),DesiredCount:c,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:y,SecurityGroups:f,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:r}]}};if(h)O.Properties.LoadBalancers=[{TargetGroupArn:h,ContainerName:n,ContainerPort:u}];return{cluster:S,taskDefinition:L,service:O,taskRole:D,executionRole:C,clusterLogicalId:A,taskDefinitionLogicalId:x,serviceLogicalId:B,taskRoleLogicalId:E,executionRoleLogicalId:P}}static createLambdaFunction(e){let{slug:n,environment:r,runtime:i,handler:s,code:a,timeout:c=30,memorySize:u=128,environmentVariables:d={},vpcConfig:m}=e,p=l({slug:n,environment:r,resourceType:"lambda"}),g=o(p),y=o(`${p}-role`),f={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}};if(m)f.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let h={Type:"AWS::Lambda::Function",Properties:{FunctionName:p,Runtime:i,Role:v.GetAtt(y,"Arn"),Handler:s,Code:{...a.s3Bucket&&{S3Bucket:a.s3Bucket},...a.s3Key&&{S3Key:a.s3Key},...a.zipFile&&{ZipFile:a.zipFile}},Timeout:c,MemorySize:u,Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r}]}};if(Object.keys(d).length>0)h.Properties.Environment={Variables:d};if(m)h.Properties.VpcConfig={SecurityGroupIds:m.securityGroupIds,SubnetIds:m.subnetIds};return{lambdaFunction:h,role:f,logicalId:g,roleLogicalId:y}}static generateNodeServerUserData(e={}){let{nodeVersion:n="20",appRepo:r,environment:i={}}=e,s=Object.entries(i).map(([a,c])=>`echo "export ${a}='${c}'" >> /etc/environment`).join(`
|
|
201
201
|
`);return`#!/bin/bash
|
|
202
202
|
# Update system
|
|
203
203
|
yum update -y
|
|
@@ -298,7 +298,7 @@ systemctl enable caddy
|
|
|
298
298
|
systemctl start caddy
|
|
299
299
|
|
|
300
300
|
echo "Bun server setup complete!"
|
|
301
|
-
`}static createLaunchConfiguration(e){let{slug:n,environment:r,imageId:i,instanceType:s,keyName:a,securityGroups:c,userData:u,volumeSize:d=20,volumeType:m="gp3",encrypted:p=!0,iamInstanceProfile:g}=e,y=l({slug:n,environment:r,resourceType:"launch-config"}),f=o(y),h={Type:"AWS::AutoScaling::LaunchConfiguration",Properties:{ImageId:i,InstanceType:s,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:d,VolumeType:m,Encrypted:p,DeleteOnTermination:!0}}]}};if(a)h.Properties.KeyName=a;if(c)h.Properties.SecurityGroups=c;if(u)h.Properties.UserData=v.Base64(u);if(g)h.Properties.IamInstanceProfile=g;return{launchConfiguration:h,logicalId:f}}static createAutoScalingGroup(e){let{slug:n,environment:r,launchConfigurationName:i,minSize:s,maxSize:a,desiredCapacity:c,vpcZoneIdentifier:u,targetGroupArns:d,healthCheckType:m="EC2",healthCheckGracePeriod:p=300,cooldown:g=300,tags:y={}}=e,f=l({slug:n,environment:r,resourceType:"asg"}),h=o(f),S={Type:"AWS::AutoScaling::AutoScalingGroup",Properties:{AutoScalingGroupName:f,LaunchConfigurationName:i,MinSize:s,MaxSize:a,HealthCheckType:m,HealthCheckGracePeriod:p,Cooldown:g,Tags:[{Key:"Name",Value:f,PropagateAtLaunch:!0},{Key:"Environment",Value:r,PropagateAtLaunch:!0},...Object.entries(y).map(([A,R])=>({Key:A,Value:R,PropagateAtLaunch:!0}))]}};if(c!==void 0)S.Properties.DesiredCapacity=c;if(u)S.Properties.VPCZoneIdentifier=u;if(d)S.Properties.TargetGroupARNs=d;return S.UpdatePolicy={AutoScalingRollingUpdate:{MaxBatchSize:1,MinInstancesInService:Math.max(0,s-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:S,logicalId:h}}static createScalingPolicy(e){let{slug:n,environment:r,autoScalingGroupName:i,policyType:s="TargetTrackingScaling",targetValue:a=70,predefinedMetricType:c="ASGAverageCPUUtilization"}=e,u=l({slug:n,environment:r,resourceType:"scaling-policy"}),d=o(u),m={Type:"AWS::AutoScaling::ScalingPolicy",Properties:{AutoScalingGroupName:i,PolicyType:s}};if(s==="TargetTrackingScaling")m.Properties.TargetTrackingConfiguration={PredefinedMetricSpecification:{PredefinedMetricType:c},TargetValue:a};return{scalingPolicy:m,logicalId:d}}static AutoScaling={smallWebServer:(e,n,r,i,s)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:2,maxSize:4,desiredCapacity:2,vpcZoneIdentifier:i,targetGroupArns:s,healthCheckType:s?"ELB":"EC2",healthCheckGracePeriod:300}),mediumWebServer:(e,n,r,i,s)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:3,maxSize:10,desiredCapacity:3,vpcZoneIdentifier:i,targetGroupArns:s,healthCheckType:s?"ELB":"EC2",healthCheckGracePeriod:300}),largeWebServer:(e,n,r,i,s)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:5,maxSize:20,desiredCapacity:5,vpcZoneIdentifier:i,targetGroupArns:s,healthCheckType:s?"ELB":"EC2",healthCheckGracePeriod:300}),cpuScaling:(e,n,r,i=70)=>b.createScalingPolicy({slug:e,environment:n,autoScalingGroupName:r,policyType:"TargetTrackingScaling",predefinedMetricType:"ASGAverageCPUUtilization",targetValue:i}),requestCountScaling:(e,n,r,i=1000)=>b.createScalingPolicy({slug:e,environment:n,autoScalingGroupName:r,policyType:"TargetTrackingScaling",predefinedMetricType:"ALBRequestCountPerTarget",targetValue:i})};static Secrets={fromSecretsManager:(e)=>Object.entries(e).map(([n,r])=>({name:n,valueFrom:r})),fromJsonSecret:(e,n)=>`${e}:${n}::`,fromSecretVersion:(e,n)=>`${e}::${n}:`,fromSecretVersionStage:(e,n)=>`${e}:::${n}`,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 n=e.region||"*",r=e.accountId||"*";return`arn:aws:secretsmanager:${n}:${r}:secret:${e.secretNamePrefix}*`},commonAppSecrets:(e)=>({DATABASE_URL:`${e}/database-url`,DATABASE_PASSWORD:`${e}/database-password`,REDIS_URL:`${e}/redis-url`,REDIS_PASSWORD:`${e}/redis-password`,API_KEY:`${e}/api-key`,JWT_SECRET:`${e}/jwt-secret`,ENCRYPTION_KEY:`${e}/encryption-key`,AWS_ACCESS_KEY_ID:`${e}/aws-access-key-id`,AWS_SECRET_ACCESS_KEY:`${e}/aws-secret-access-key`,MAIL_PASSWORD:`${e}/mail-password`,STRIPE_SECRET_KEY:`${e}/stripe-secret-key`,STRIPE_WEBHOOK_SECRET:`${e}/stripe-webhook-secret`})};static createFargateServiceWithSecrets(e){let{secretArns:n=[],kmsKeyArns:r=[],...i}=e,s=b.createFargateService(i);if(n.length>0){if(!s.executionRole.Properties.Policies)s.executionRole.Properties.Policies=[];if(s.executionRole.Properties.Policies.push(b.Secrets.createAccessPolicy(n)),r.length>0)s.executionRole.Properties.Policies.push(b.Secrets.createKmsPolicy(r))}return s}static generateSecretReferences(e){return e.secrets.map((n)=>{let r=`arn:aws:secretsmanager:${e.region}:${e.accountId}:secret:${e.secretPrefix}/${n}`;return{name:n.toUpperCase().replace(/-/g,"_"),valueFrom:r}})}static EnvSecrets={database:(e)=>[{name:"DB_HOST",valueFrom:`${e}:host::`},{name:"DB_PORT",valueFrom:`${e}:port::`},{name:"DB_USERNAME",valueFrom:`${e}:username::`},{name:"DB_PASSWORD",valueFrom:`${e}:password::`},{name:"DB_NAME",valueFrom:`${e}:dbname::`}],redis:(e)=>[{name:"REDIS_HOST",valueFrom:`${e}:host::`},{name:"REDIS_PORT",valueFrom:`${e}:port::`},{name:"REDIS_PASSWORD",valueFrom:`${e}:password::`}],apiCredentials:(e)=>[{name:"API_KEY",valueFrom:`${e}:apiKey::`},{name:"API_SECRET",valueFrom:`${e}:apiSecret::`}],mail:(e)=>[{name:"MAIL_HOST",valueFrom:`${e}:host::`},{name:"MAIL_PORT",valueFrom:`${e}:port::`},{name:"MAIL_USERNAME",valueFrom:`${e}:username::`},{name:"MAIL_PASSWORD",valueFrom:`${e}:password::`}],awsCredentials:(e)=>[{name:"AWS_ACCESS_KEY_ID",valueFrom:`${e}:accessKeyId::`},{name:"AWS_SECRET_ACCESS_KEY",valueFrom:`${e}:secretAccessKey::`}]};static createJumpBox(e){let{slug:n,environment:r,vpcId:i,subnetId:s,keyName:a,instanceType:c="t3.micro",imageId:u=
|
|
301
|
+
`}static createLaunchConfiguration(e){let{slug:n,environment:r,imageId:i,instanceType:s,keyName:a,securityGroups:c,userData:u,volumeSize:d=20,volumeType:m="gp3",encrypted:p=!0,iamInstanceProfile:g}=e,y=l({slug:n,environment:r,resourceType:"launch-config"}),f=o(y),h={Type:"AWS::AutoScaling::LaunchConfiguration",Properties:{ImageId:i,InstanceType:s,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:d,VolumeType:m,Encrypted:p,DeleteOnTermination:!0}}]}};if(a)h.Properties.KeyName=a;if(c)h.Properties.SecurityGroups=c;if(u)h.Properties.UserData=v.Base64(u);if(g)h.Properties.IamInstanceProfile=g;return{launchConfiguration:h,logicalId:f}}static createAutoScalingGroup(e){let{slug:n,environment:r,launchConfigurationName:i,minSize:s,maxSize:a,desiredCapacity:c,vpcZoneIdentifier:u,targetGroupArns:d,healthCheckType:m="EC2",healthCheckGracePeriod:p=300,cooldown:g=300,tags:y={}}=e,f=l({slug:n,environment:r,resourceType:"asg"}),h=o(f),S={Type:"AWS::AutoScaling::AutoScalingGroup",Properties:{AutoScalingGroupName:f,LaunchConfigurationName:i,MinSize:s,MaxSize:a,HealthCheckType:m,HealthCheckGracePeriod:p,Cooldown:g,Tags:[{Key:"Name",Value:f,PropagateAtLaunch:!0},{Key:"Environment",Value:r,PropagateAtLaunch:!0},...Object.entries(y).map(([A,R])=>({Key:A,Value:R,PropagateAtLaunch:!0}))]}};if(c!==void 0)S.Properties.DesiredCapacity=c;if(u)S.Properties.VPCZoneIdentifier=u;if(d)S.Properties.TargetGroupARNs=d;return S.UpdatePolicy={AutoScalingRollingUpdate:{MaxBatchSize:1,MinInstancesInService:Math.max(0,s-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:S,logicalId:h}}static createScalingPolicy(e){let{slug:n,environment:r,autoScalingGroupName:i,policyType:s="TargetTrackingScaling",targetValue:a=70,predefinedMetricType:c="ASGAverageCPUUtilization"}=e,u=l({slug:n,environment:r,resourceType:"scaling-policy"}),d=o(u),m={Type:"AWS::AutoScaling::ScalingPolicy",Properties:{AutoScalingGroupName:i,PolicyType:s}};if(s==="TargetTrackingScaling")m.Properties.TargetTrackingConfiguration={PredefinedMetricSpecification:{PredefinedMetricType:c},TargetValue:a};return{scalingPolicy:m,logicalId:d}}static AutoScaling={smallWebServer:(e,n,r,i,s)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:2,maxSize:4,desiredCapacity:2,vpcZoneIdentifier:i,targetGroupArns:s,healthCheckType:s?"ELB":"EC2",healthCheckGracePeriod:300}),mediumWebServer:(e,n,r,i,s)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:3,maxSize:10,desiredCapacity:3,vpcZoneIdentifier:i,targetGroupArns:s,healthCheckType:s?"ELB":"EC2",healthCheckGracePeriod:300}),largeWebServer:(e,n,r,i,s)=>b.createAutoScalingGroup({slug:e,environment:n,launchConfigurationName:r,minSize:5,maxSize:20,desiredCapacity:5,vpcZoneIdentifier:i,targetGroupArns:s,healthCheckType:s?"ELB":"EC2",healthCheckGracePeriod:300}),cpuScaling:(e,n,r,i=70)=>b.createScalingPolicy({slug:e,environment:n,autoScalingGroupName:r,policyType:"TargetTrackingScaling",predefinedMetricType:"ASGAverageCPUUtilization",targetValue:i}),requestCountScaling:(e,n,r,i=1000)=>b.createScalingPolicy({slug:e,environment:n,autoScalingGroupName:r,policyType:"TargetTrackingScaling",predefinedMetricType:"ALBRequestCountPerTarget",targetValue:i})};static Secrets={fromSecretsManager:(e)=>Object.entries(e).map(([n,r])=>({name:n,valueFrom:r})),fromJsonSecret:(e,n)=>`${e}:${n}::`,fromSecretVersion:(e,n)=>`${e}::${n}:`,fromSecretVersionStage:(e,n)=>`${e}:::${n}`,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 n=e.region||"*",r=e.accountId||"*";return`arn:aws:secretsmanager:${n}:${r}:secret:${e.secretNamePrefix}*`},commonAppSecrets:(e)=>({DATABASE_URL:`${e}/database-url`,DATABASE_PASSWORD:`${e}/database-password`,REDIS_URL:`${e}/redis-url`,REDIS_PASSWORD:`${e}/redis-password`,API_KEY:`${e}/api-key`,JWT_SECRET:`${e}/jwt-secret`,ENCRYPTION_KEY:`${e}/encryption-key`,AWS_ACCESS_KEY_ID:`${e}/aws-access-key-id`,AWS_SECRET_ACCESS_KEY:`${e}/aws-secret-access-key`,MAIL_PASSWORD:`${e}/mail-password`,STRIPE_SECRET_KEY:`${e}/stripe-secret-key`,STRIPE_WEBHOOK_SECRET:`${e}/stripe-webhook-secret`})};static createFargateServiceWithSecrets(e){let{secretArns:n=[],kmsKeyArns:r=[],...i}=e,s=b.createFargateService(i);if(n.length>0){if(!s.executionRole.Properties.Policies)s.executionRole.Properties.Policies=[];if(s.executionRole.Properties.Policies.push(b.Secrets.createAccessPolicy(n)),r.length>0)s.executionRole.Properties.Policies.push(b.Secrets.createKmsPolicy(r))}return s}static generateSecretReferences(e){return e.secrets.map((n)=>{let r=`arn:aws:secretsmanager:${e.region}:${e.accountId}:secret:${e.secretPrefix}/${n}`;return{name:n.toUpperCase().replace(/-/g,"_"),valueFrom:r}})}static EnvSecrets={database:(e)=>[{name:"DB_HOST",valueFrom:`${e}:host::`},{name:"DB_PORT",valueFrom:`${e}:port::`},{name:"DB_USERNAME",valueFrom:`${e}:username::`},{name:"DB_PASSWORD",valueFrom:`${e}:password::`},{name:"DB_NAME",valueFrom:`${e}:dbname::`}],redis:(e)=>[{name:"REDIS_HOST",valueFrom:`${e}:host::`},{name:"REDIS_PORT",valueFrom:`${e}:port::`},{name:"REDIS_PASSWORD",valueFrom:`${e}:password::`}],apiCredentials:(e)=>[{name:"API_KEY",valueFrom:`${e}:apiKey::`},{name:"API_SECRET",valueFrom:`${e}:apiSecret::`}],mail:(e)=>[{name:"MAIL_HOST",valueFrom:`${e}:host::`},{name:"MAIL_PORT",valueFrom:`${e}:port::`},{name:"MAIL_USERNAME",valueFrom:`${e}:username::`},{name:"MAIL_PASSWORD",valueFrom:`${e}:password::`}],awsCredentials:(e)=>[{name:"AWS_ACCESS_KEY_ID",valueFrom:`${e}:accessKeyId::`},{name:"AWS_SECRET_ACCESS_KEY",valueFrom:`${e}:secretAccessKey::`}]};static createJumpBox(e){let{slug:n,environment:r,vpcId:i,subnetId:s,keyName:a,instanceType:c="t3.micro",imageId:u=Cl(c),mountEfs:d,databaseTools:m=!1}=e,p=e.allowedCidrs??(a?["0.0.0.0/0"]:[]),g=l({slug:n,environment:r,resourceType:"jumpbox"}),y=o(`${g}-sg`),f={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:`${g}-sg`,GroupDescription:`Security group for ${g} JumpBox access`,VpcId:i,SecurityGroupIngress:p.map((x)=>({IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:x,Description:`SSH access from ${x}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound traffic"}],Tags:[{Key:"Name",Value:`${g}-sg`},{Key:"Environment",Value:r}]}},h=o(`${g}-role`),S={Type:"AWS::IAM::Role",Properties:{RoleName:`${g}-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:d?[{PolicyName:"EFSAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess"],Resource:"*"}]}}]:void 0}},A=o(`${g}-profile`),R={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:`${g}-profile`,Roles:[v.Ref(h)]}},P=`#!/bin/bash
|
|
302
302
|
dnf install -y amazon-efs-utils nfs-utils jq wget htop
|
|
303
303
|
`;if(m)P+=`
|
|
304
304
|
# Database clients: psql, mysql (MariaDB), redis-cli
|
|
@@ -569,7 +569,7 @@ ufw default allow outgoing
|
|
|
569
569
|
${e.map((n)=>`ufw allow ${n}`).join(`
|
|
570
570
|
`)}
|
|
571
571
|
ufw --force enable
|
|
572
|
-
`},Presets:{bunWithNginx:(e,n=3000)=>b.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:e,appPort:n,enableSsl:!0}),bunWithCaddy:(e,n=3000)=>b.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:e,appPort:n,enableSsl:!1}),nodeWithPm2:(e,n=3000)=>b.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:e,appPort:n,enableSsl:!0}),worker:(e="bun")=>b.UserData.generateAppServerScript({runtime:e,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(e){let{slug:n,environment:r,domain:i,instanceLogicalId:s}=e,a=l({slug:n,environment:r,resourceType:"eip"}),c=o(a),u={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r},...i?[{Key:"Domain",Value:i}]:[]]}},d={[c]:u},m,p;if(s)p=o(`${a}-assoc`),m={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:v.GetAtt(c,"AllocationId"),InstanceId:v.Ref(s)}},d[p]=m;return{eip:u,eipAssociation:m,eipLogicalId:c,associationLogicalId:p,resources:d}}static createServerModeStack(e){let{slug:n,environment:r,vpcId:i,subnetId:s,instanceType:a="t3.small",imageId:c="ami-0f3caa1cf4417e51b",keyName:u,domain:d,userData:m,allowedPorts:p=[22,80,443],volumeSize:g=20,volumeType:y="gp3"}=e,f={},h=l({slug:n,environment:r,resourceType:"server-sg"}),S=o(h),A={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:h,GroupDescription:`Security group for ${n} server`,VpcId:i,SecurityGroupIngress:p.map((K)=>({IpProtocol:"tcp",FromPort:K,ToPort:K,CidrIp:"0.0.0.0/0",Description:`Port ${K}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};f[S]=A;let R=l({slug:n,environment:r,resourceType:"server-role"}),P=o(R),C={Type:"AWS::IAM::Role",Properties:{RoleName:R,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:"*"}]}}]}};f[P]=C;let E=l({slug:n,environment:r,resourceType:"server-profile"}),D=o(E),x={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:E,Roles:[v.Ref(P)]}};f[D]=x;let L=l({slug:n,environment:r,resourceType:"server"}),B=o(L),O={Type:"AWS::EC2::Instance",DependsOn:[D],Properties:{ImageId:c,InstanceType:a,KeyName:u,SubnetId:s,SecurityGroupIds:[v.Ref(S)],IamInstanceProfile:v.Ref(D),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:g,VolumeType:y,Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:L},{Key:"Environment",Value:r},...d?[{Key:"Domain",Value:d}]:[]]}};if(m)O.Properties.UserData=v.Base64(m);f[B]=O;let{eip:F,eipAssociation:V,eipLogicalId:
|
|
572
|
+
`},Presets:{bunWithNginx:(e,n=3000)=>b.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:e,appPort:n,enableSsl:!0}),bunWithCaddy:(e,n=3000)=>b.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:e,appPort:n,enableSsl:!1}),nodeWithPm2:(e,n=3000)=>b.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:e,appPort:n,enableSsl:!0}),worker:(e="bun")=>b.UserData.generateAppServerScript({runtime:e,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(e){let{slug:n,environment:r,domain:i,instanceLogicalId:s}=e,a=l({slug:n,environment:r,resourceType:"eip"}),c=o(a),u={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r},...i?[{Key:"Domain",Value:i}]:[]]}},d={[c]:u},m,p;if(s)p=o(`${a}-assoc`),m={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:v.GetAtt(c,"AllocationId"),InstanceId:v.Ref(s)}},d[p]=m;return{eip:u,eipAssociation:m,eipLogicalId:c,associationLogicalId:p,resources:d}}static createServerModeStack(e){let{slug:n,environment:r,vpcId:i,subnetId:s,instanceType:a="t3.small",imageId:c="ami-0f3caa1cf4417e51b",keyName:u,domain:d,userData:m,allowedPorts:p=[22,80,443],volumeSize:g=20,volumeType:y="gp3"}=e,f={},h=l({slug:n,environment:r,resourceType:"server-sg"}),S=o(h),A={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:h,GroupDescription:`Security group for ${n} server`,VpcId:i,SecurityGroupIngress:p.map((K)=>({IpProtocol:"tcp",FromPort:K,ToPort:K,CidrIp:"0.0.0.0/0",Description:`Port ${K}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};f[S]=A;let R=l({slug:n,environment:r,resourceType:"server-role"}),P=o(R),C={Type:"AWS::IAM::Role",Properties:{RoleName:R,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:"*"}]}}]}};f[P]=C;let E=l({slug:n,environment:r,resourceType:"server-profile"}),D=o(E),x={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:E,Roles:[v.Ref(P)]}};f[D]=x;let L=l({slug:n,environment:r,resourceType:"server"}),B=o(L),O={Type:"AWS::EC2::Instance",DependsOn:[D],Properties:{ImageId:c,InstanceType:a,KeyName:u,SubnetId:s,SecurityGroupIds:[v.Ref(S)],IamInstanceProfile:v.Ref(D),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:g,VolumeType:y,Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:L},{Key:"Environment",Value:r},...d?[{Key:"Domain",Value:d}]:[]]}};if(m)O.Properties.UserData=v.Base64(m);f[B]=O;let{eip:F,eipAssociation:V,eipLogicalId:le,associationLogicalId:q,resources:J}=b.createElasticIp({slug:n,environment:r,domain:d,instanceLogicalId:B});return Object.assign(f,J),{instance:O,securityGroup:A,eip:F,eipAssociation:V,instanceRole:C,instanceProfile:x,resources:f,outputs:{instanceLogicalId:B,securityGroupLogicalId:S,eipLogicalId:le,associationLogicalId:q,roleLogicalId:P,profileLogicalId:D}}}static ServerMode={webServer:(e)=>{let n=b.UserData.generateAppServerScript({runtime:e.runtime||"bun",webServer:e.webServer||"nginx",domain:e.domain,enableSsl:!0});return b.createServerModeStack({...e,userData:n,instanceType:"t3.small",allowedPorts:[22,80,443]})},workerServer:(e)=>{let n=b.UserData.generateAppServerScript({runtime:e.runtime||"bun",webServer:"none",installRedis:e.installRedis});return b.createServerModeStack({...e,userData:n,instanceType:"t3.medium",allowedPorts:[22]})},cacheServer:(e)=>b.createServerModeStack({...e,userData:`#!/bin/bash
|
|
573
573
|
set -e
|
|
574
574
|
apt-get update && apt-get upgrade -y
|
|
575
575
|
apt-get install -y redis-server
|
|
@@ -577,7 +577,7 @@ sed -i 's/bind 127.0.0.1/bind 0.0.0.0/' /etc/redis/redis.conf
|
|
|
577
577
|
systemctl enable redis-server
|
|
578
578
|
systemctl restart redis-server
|
|
579
579
|
echo "Redis server setup complete!"
|
|
580
|
-
`,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class M{static createVpc(e){let{slug:n,environment:r,cidr:i="10.0.0.0/16",enableDnsHostnames:s=!0,enableDnsSupport:a=!0}=e,c=l({slug:n,environment:r,resourceType:"vpc"}),u=o(c);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:i,EnableDnsHostnames:s,EnableDnsSupport:a,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}},logicalId:u}}static createSubnet(e){let{slug:n,environment:r,vpcId:i,type:s,cidr:a,availabilityZone:c,mapPublicIp:u=s==="public"}=e,d=l({slug:n,environment:r,resourceType:`subnet-${s}`}),m=o(`${d}-${c}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:i,CidrBlock:a,AvailabilityZone:c,MapPublicIpOnLaunch:u,Tags:[{Key:"Name",Value:`${d}-${c}`},{Key:"Environment",Value:r},{Key:"Type",Value:s}]}},logicalId:m}}static createInternetGateway(e,n){let r=l({slug:e,environment:n,resourceType:"igw"}),i=o(r);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static attachInternetGateway(e,n){let r=o(`${e}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:v.Ref(e),InternetGatewayId:v.Ref(n)}},logicalId:r}}static createEip(e,n){let r=l({slug:e,environment:n,resourceType:"eip"}),i=o(r);return{eip:{Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static createNatGateway(e,n){let{slug:r,environment:i,subnetId:s}=e,a=l({slug:r,environment:i,resourceType:"nat"}),c=o(a);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:v.GetAtt(n,"AllocationId"),SubnetId:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:c}}static createRouteTable(e,n,r,i){let s=l({slug:e,environment:n,resourceType:`rt-${i}`}),a=o(s);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:v.Ref(r),Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:n},{Key:"Type",Value:i}]}},logicalId:a}}static createRoute(e,n,r){let i=o(`${e}-route-${r.type}`),s={Type:"AWS::EC2::Route",Properties:{RouteTableId:v.Ref(e),DestinationCidrBlock:n}};if(r.type==="igw")s.Properties.GatewayId=v.Ref(r.logicalId);else if(r.type==="nat")s.Properties.NatGatewayId=v.Ref(r.logicalId);else if(r.type==="instance")s.Properties.InstanceId=v.Ref(r.logicalId);return{route:s,logicalId:i}}static associateSubnetWithRouteTable(e,n){let r=o(`${e}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:v.Ref(e),RouteTableId:v.Ref(n)}},logicalId:r}}static enableFlowLogs(e){let{slug:n,environment:r,resourceId:i,resourceType:s,trafficType:a="ALL",logGroupName:c}=e,u=l({slug:n,environment:r,resourceType:"flowlog"}),d=o(u);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:s,ResourceIds:[i],TrafficType:a,LogDestinationType:"cloud-watch-logs",LogGroupName:c||`/aws/vpc/${n}-${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static calculateSubnetCidrs(e,n,r=3){let[i,s]=e.split("/"),a=Number.parseInt(s,10),c=Math.ceil(Math.log2(n*r)),u=a+c;if(u>28)throw Error("VPC CIDR is too small to accommodate requested subnets");let[d,m,p,g]=i.split(".").map(Number),y=(d<<24)+(m<<16)+(p<<8)+g,f=2**(32-u),h=[];for(let S=0;S<n*r;S++){let A=y+S*f,R=[A>>>24&255,A>>>16&255,A>>>8&255,A&255].join(".");h.push(`${R}/${u}`)}return h}static getAvailabilityZones(e,n){return["a","b","c","d","e","f"].slice(0,n).map((i)=>`${e}${i}`)}static createMultiAzNetwork(e){let{slug:n,environment:r,region:i,cidr:s="10.0.0.0/16",zones:a=3,enableNatGateway:c=!1,singleNatGateway:u=!1,enableFlowLogs:d=!1}=e,m={},p=[],g=[],y=[],{vpc:f,logicalId:h}=M.createVpc({slug:n,environment:r,cidr:s});m[h]=f;let{internetGateway:S,logicalId:A}=M.createInternetGateway(n,r);m[A]=S;let{attachment:R,logicalId:P}=M.attachInternetGateway(h,A);m[P]=R;let{routeTable:C,logicalId:E}=M.createRouteTable(n,r,h,"public");m[E]=C;let{route:D,logicalId:x}=M.createRoute(E,"0.0.0.0/0",{type:"igw",logicalId:A});D.DependsOn=P,m[x]=D;let L=M.calculateSubnetCidrs(s,a,2),B=M.getAvailabilityZones(i,a),O=[];for(let F=0;F<a;F++){let V=B[F],
|
|
580
|
+
`,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class M{static createVpc(e){let{slug:n,environment:r,cidr:i="10.0.0.0/16",enableDnsHostnames:s=!0,enableDnsSupport:a=!0}=e,c=l({slug:n,environment:r,resourceType:"vpc"}),u=o(c);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:i,EnableDnsHostnames:s,EnableDnsSupport:a,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}},logicalId:u}}static createSubnet(e){let{slug:n,environment:r,vpcId:i,type:s,cidr:a,availabilityZone:c,mapPublicIp:u=s==="public"}=e,d=l({slug:n,environment:r,resourceType:`subnet-${s}`}),m=o(`${d}-${c}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:i,CidrBlock:a,AvailabilityZone:c,MapPublicIpOnLaunch:u,Tags:[{Key:"Name",Value:`${d}-${c}`},{Key:"Environment",Value:r},{Key:"Type",Value:s}]}},logicalId:m}}static createInternetGateway(e,n){let r=l({slug:e,environment:n,resourceType:"igw"}),i=o(r);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static attachInternetGateway(e,n){let r=o(`${e}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:v.Ref(e),InternetGatewayId:v.Ref(n)}},logicalId:r}}static createEip(e,n){let r=l({slug:e,environment:n,resourceType:"eip"}),i=o(r);return{eip:{Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:r},{Key:"Environment",Value:n}]}},logicalId:i}}static createNatGateway(e,n){let{slug:r,environment:i,subnetId:s}=e,a=l({slug:r,environment:i,resourceType:"nat"}),c=o(a);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:v.GetAtt(n,"AllocationId"),SubnetId:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:c}}static createRouteTable(e,n,r,i){let s=l({slug:e,environment:n,resourceType:`rt-${i}`}),a=o(s);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:v.Ref(r),Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:n},{Key:"Type",Value:i}]}},logicalId:a}}static createRoute(e,n,r){let i=o(`${e}-route-${r.type}`),s={Type:"AWS::EC2::Route",Properties:{RouteTableId:v.Ref(e),DestinationCidrBlock:n}};if(r.type==="igw")s.Properties.GatewayId=v.Ref(r.logicalId);else if(r.type==="nat")s.Properties.NatGatewayId=v.Ref(r.logicalId);else if(r.type==="instance")s.Properties.InstanceId=v.Ref(r.logicalId);return{route:s,logicalId:i}}static associateSubnetWithRouteTable(e,n){let r=o(`${e}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:v.Ref(e),RouteTableId:v.Ref(n)}},logicalId:r}}static enableFlowLogs(e){let{slug:n,environment:r,resourceId:i,resourceType:s,trafficType:a="ALL",logGroupName:c}=e,u=l({slug:n,environment:r,resourceType:"flowlog"}),d=o(u);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:s,ResourceIds:[i],TrafficType:a,LogDestinationType:"cloud-watch-logs",LogGroupName:c||`/aws/vpc/${n}-${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static calculateSubnetCidrs(e,n,r=3){let[i,s]=e.split("/"),a=Number.parseInt(s,10),c=Math.ceil(Math.log2(n*r)),u=a+c;if(u>28)throw Error("VPC CIDR is too small to accommodate requested subnets");let[d,m,p,g]=i.split(".").map(Number),y=(d<<24)+(m<<16)+(p<<8)+g,f=2**(32-u),h=[];for(let S=0;S<n*r;S++){let A=y+S*f,R=[A>>>24&255,A>>>16&255,A>>>8&255,A&255].join(".");h.push(`${R}/${u}`)}return h}static getAvailabilityZones(e,n){return["a","b","c","d","e","f"].slice(0,n).map((i)=>`${e}${i}`)}static createMultiAzNetwork(e){let{slug:n,environment:r,region:i,cidr:s="10.0.0.0/16",zones:a=3,enableNatGateway:c=!1,singleNatGateway:u=!1,enableFlowLogs:d=!1}=e,m={},p=[],g=[],y=[],{vpc:f,logicalId:h}=M.createVpc({slug:n,environment:r,cidr:s});m[h]=f;let{internetGateway:S,logicalId:A}=M.createInternetGateway(n,r);m[A]=S;let{attachment:R,logicalId:P}=M.attachInternetGateway(h,A);m[P]=R;let{routeTable:C,logicalId:E}=M.createRouteTable(n,r,h,"public");m[E]=C;let{route:D,logicalId:x}=M.createRoute(E,"0.0.0.0/0",{type:"igw",logicalId:A});D.DependsOn=P,m[x]=D;let L=M.calculateSubnetCidrs(s,a,2),B=M.getAvailabilityZones(i,a),O=[];for(let F=0;F<a;F++){let V=B[F],le=L[F*2],q=L[F*2+1],{subnet:J,logicalId:K}=M.createSubnet({slug:n,environment:r,vpcId:v.Ref(h),type:"public",cidr:le,availabilityZone:V});m[K]=J,p.push(K);let{association:z,logicalId:ye}=M.associateSubnetWithRouteTable(K,E);m[ye]=z;let{subnet:Te,logicalId:re}=M.createSubnet({slug:n,environment:r,vpcId:v.Ref(h),type:"private",cidr:q,availabilityZone:V});if(m[re]=Te,g.push(re),c&&(!u||F===0)){let{eip:te,logicalId:ie}=M.createEip(`${n}-${V}`,r);m[ie]=te;let{natGateway:fe,logicalId:ae}=M.createNatGateway({slug:`${n}-${V}`,environment:r,subnetId:v.Ref(K)},ie);fe.DependsOn=P,m[ae]=fe,y.push(ae);let{routeTable:de,logicalId:Ee}=M.createRouteTable(`${n}-${V}`,r,h,"private");m[Ee]=de,O.push(Ee);let{route:Be,logicalId:k}=M.createRoute(Ee,"0.0.0.0/0",{type:"nat",logicalId:ae});m[k]=Be;let{association:G,logicalId:W}=M.associateSubnetWithRouteTable(re,Ee);m[W]=G}else if(c&&u&&F>0){let{association:te,logicalId:ie}=M.associateSubnetWithRouteTable(re,O[0]);m[ie]=te}else{let{routeTable:te,logicalId:ie}=M.createRouteTable(`${n}-${V}-isolated`,r,h,"private");m[ie]=te;let{association:fe,logicalId:ae}=M.associateSubnetWithRouteTable(re,ie);m[ae]=fe}}if(d){let{flowLog:F,logicalId:V}=M.enableFlowLogs({slug:n,environment:r,resourceId:v.Ref(h),resourceType:"VPC"});m[V]=F}return{resources:m,outputs:{vpcId:h,publicSubnetIds:p,privateSubnetIds:g,natGatewayIds:y.length>0?y:void 0}}}static NatGatewayCostWarning=`
|
|
581
581
|
⚠️ NAT Gateway Cost Warning:
|
|
582
582
|
- Each NAT Gateway costs approximately $32-45/month (hourly charges)
|
|
583
583
|
- Data processing charges: $0.045/GB processed
|
|
@@ -585,7 +585,7 @@ echo "Redis server setup complete!"
|
|
|
585
585
|
- Using a single NAT Gateway (singleNatGateway: true)
|
|
586
586
|
- Using NAT Instances instead (cheaper but requires management)
|
|
587
587
|
- Disabling NAT entirely for isolated private subnets
|
|
588
|
-
`}class at{static createFileSystem(e){let{slug:n,environment:r,encrypted:i=!0,kmsKeyId:s,performanceMode:a="generalPurpose",throughputMode:c="bursting",provisionedThroughput:u,enableBackup:d=!0}=e,m=l({slug:n,environment:r,resourceType:"efs"}),p=o(m),g={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:i,PerformanceMode:a,ThroughputMode:c,FileSystemTags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(s)g.Properties.KmsKeyId=s;if(c==="provisioned"&&u)g.Properties.ProvisionedThroughputInMibps=u;if(d)g.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:g,logicalId:p}}static createMountTarget(e,n){let{slug:r,environment:i,subnetId:s,securityGroups:a,ipAddress:c}=n,u=l({slug:r,environment:i,resourceType:"efs-mt"}),d=o(`${u}-${s}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:v.Ref(e),SubnetId:s,SecurityGroups:a}};if(c)m.Properties.IpAddress=c;return{mountTarget:m,logicalId:d}}static createAccessPoint(e,n){let{slug:r,environment:i,path:s="/",uid:a="1000",gid:c="1000",permissions:u="755"}=n,d=l({slug:r,environment:i,resourceType:"efs-ap"}),m=o(`${d}-${s.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:v.Ref(e),PosixUser:{Uid:a,Gid:c},RootDirectory:{Path:s,CreationInfo:{OwnerUid:a,OwnerGid:c,Permissions:u}},AccessPointTags:[{Key:"Name",Value:`${d}-${s}`},{Key:"Environment",Value:i}]}},logicalId:m}}static setLifecyclePolicy(e,n){let{transitionToIA:r,transitionToPrimary:i=!1}=n;if(!e.Properties)e.Properties={};if(e.Properties.LifecyclePolicies=[],r){let s=`AFTER_${r}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:s})}if(i)e.Properties.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"});return e}static enableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"ENABLED"},e}static disableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"DISABLED"},e}static setProvisionedThroughput(e,n){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="provisioned",e.Properties.ProvisionedThroughputInMibps=n,e}static setElasticThroughput(e){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="elastic",e}static enableMaxIO(e){if(!e.Properties)e.Properties={};return e.Properties.PerformanceMode="maxIO",e}static createEfsSecurityGroup(e){let{slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:s=[],sourceCidrBlocks:a=[],description:c}=e,u=l({slug:n,environment:r,resourceType:"efs-sg"}),d=o(u),m=[];for(let g of s)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:g,Description:"NFS from security group"});for(let g of a)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:g,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:u,GroupDescription:c||`Security group for EFS mount targets - ${n} ${r}`,VpcId:i,SecurityGroupIngress:m,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static createMultiAzMountTargets(e,n){let{slug:r,environment:i,subnetIds:s,securityGroupId:a}=n,c=[],u=[];for(let d=0;d<s.length;d++){let m=s[d],p=l({slug:r,environment:i,resourceType:"efs-mt"}),g=o(`${p}-az${d+1}`),y={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:v.Ref(e),SubnetId:m,SecurityGroups:[a]}};c.push(y),u.push(g)}return{mountTargets:c,logicalIds:u}}static createCompleteFileSystem(e){let{slug:n,environment:r,vpcId:i,subnetIds:s,sourceSecurityGroupIds:a=[],encrypted:c=!0,performanceMode:u="generalPurpose",throughputMode:d="elastic",enableBackup:m=!0,transitionToIA:p}=e,g={},{fileSystem:y,logicalId:f}=at.createFileSystem({slug:n,environment:r,encrypted:c,performanceMode:u,throughputMode:d,enableBackup:m});if(p)at.setLifecyclePolicy(y,{transitionToIA:p,transitionToPrimary:!0});g[f]=y;let{securityGroup:h,logicalId:S}=at.createEfsSecurityGroup({slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:a});g[S]=h;let{mountTargets:A,logicalIds:R}=at.createMultiAzMountTargets(f,{slug:n,environment:r,subnetIds:s,securityGroupId:v.Ref(S)});for(let P=0;P<A.length;P++)g[R[P]]=A[P];return{resources:g,outputs:{fileSystemId:f,securityGroupId:S,mountTargetIds:R}}}}class N{static verifyDomain(e){let{domain:n,slug:r,environment:i,enableDkim:s=!0,dkimKeyLength:a="RSA_2048_BIT"}=e,c=l({slug:r,environment:i,resourceType:"ses-identity"}),u=o(`${c}-${n.replace(/\./g,"")}`),d={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:n,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(s)d.Properties.DkimSigningAttributes={NextSigningKeyLength:a};return{emailIdentity:d,logicalId:u}}static createDkimRecords(e,n,r){let i=[];for(let s=0;s<n.length;s++){let a=n[s],c=o(`dkim-${e.replace(/\./g,"")}-${s+1}`),u={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`${a}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${a}.dkim.amazonses.com`]}};i.push({record:u,logicalId:c})}return i}static createConfigurationSet(e){let{slug:n,environment:r,name:i,reputationMetrics:s=!0,sendingEnabled:a=!0,suppressBounces:c=!0,suppressComplaints:u=!0}=e,d=i||l({slug:n,environment:r,resourceType:"ses-config"}),m=o(d),p=[];if(c)p.push("BOUNCE");if(u)p.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:d,ReputationOptions:{ReputationMetricsEnabled:s},SendingOptions:{SendingEnabled:a},SuppressionOptions:{SuppressedReasons:p}}},logicalId:m}}static createReceiptRuleSet(e){let{slug:n,environment:r,name:i}=e,s=i||l({slug:n,environment:r,resourceType:"ses-ruleset"}),a=o(s);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:s}},logicalId:a}}static createReceiptRule(e,n){let{slug:r,environment:i,ruleSetName:s,recipients:a,enabled:c=!0,scanEnabled:u=!0,tlsPolicy:d="Require",s3Action:m,lambdaAction:p,snsAction:g}=n,y=l({slug:r,environment:i,resourceType:"ses-rule"}),f=o(y),h=[];if(m)h.push({S3Action:{BucketName:m.bucketName,ObjectKeyPrefix:m.prefix,KmsKeyArn:m.kmsKeyArn}});if(p)h.push({LambdaAction:{FunctionArn:p.functionArn,InvocationType:p.invocationType||"Event"}});if(g)h.push({SNSAction:{TopicArn:g.topicArn,Encoding:g.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:s,Rule:{Name:y,Enabled:c,ScanEnabled:u,TlsPolicy:d,Recipients:a,Actions:h.length>0?h:void 0}}},logicalId:f}}static createMxRecord(e,n,r){let i=o(`mx-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${r}.amazonaws.com`]}},logicalId:i}}static createVerificationRecord(e,n,r){let i=o(`verification-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`_amazonses.${e}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${n}"`]}},logicalId:i}}static getSmtpEndpoint(e){return`email-smtp.${e}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(e,n,r){let{includeDomains:i=[],softFail:s=!1}=r||{},a=o(`spf-${e.replace(/\./g,"")}`),c="v=spf1 include:amazonses.com";for(let d of i)c+=` include:${d}`;return c+=s?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${c}"`]}},logicalId:a}}static createDmarcRecord(e,n,r){let{policy:i="none",subdomainPolicy:s,percentage:a=100,reportingEmail:c,forensicEmail:u}=r||{},d=o(`dmarc-${e.replace(/\./g,"")}`),m=`v=DMARC1; p=${i}; pct=${a}`;if(s)m+=`; sp=${s}`;if(c)m+=`; rua=mailto:${c}`;if(u)m+=`; ruf=mailto:${u}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:`_dmarc.${e}`,Type:"TXT",TTL:300,ResourceRecords:[`"${m}"`]}},logicalId:d}}static createInboundEmailSetup(e){let{slug:n,environment:r,domain:i,s3BucketName:s,s3KeyPrefix:a="inbound/",region:c,hostedZoneId:u,lambdaFunctionArn:d,snsTopicArn:m}=e,p={},{ruleSet:g,logicalId:y}=N.createReceiptRuleSet({slug:n,environment:r});p[y]=g;let{receiptRule:f,logicalId:h}=N.createReceiptRule(y,{slug:n,environment:r,ruleSetName:g.Properties.RuleSetName||`${n}-${r}-receipt-rule-set`,recipients:[i],s3Action:{bucketName:s,prefix:a},lambdaAction:d?{functionArn:d,invocationType:"Event"}:void 0,snsAction:m?{topicArn:m}:void 0});p[h]=f;let{record:S,logicalId:A}=N.createMxRecord(i,u,c);return p[A]=S,{resources:p,outputs:{ruleSetLogicalId:y,ruleLogicalId:h,mxRecordLogicalId:A}}}static createCompleteDomainSetup(e){let{slug:n,environment:r,domain:i,hostedZoneId:s,region:a,enableInbound:c=!1,inboundS3Bucket:u,dmarcReportingEmail:d}=e,m={},{emailIdentity:p,logicalId:g}=N.verifyDomain({domain:i,slug:n,environment:r});m[g]=p;let{configurationSet:y,logicalId:f}=N.createConfigurationSet({slug:n,environment:r});m[f]=y;let{record:h,logicalId:S}=N.createSpfRecord(i,s);m[S]=h;let{record:A,logicalId:R}=N.createDmarcRecord(i,s,{policy:"none",reportingEmail:d||`dmarc-reports@${i}`});if(m[R]=A,c&&u){let P=N.createInboundEmailSetup({slug:n,environment:r,domain:i,s3BucketName:u,region:a,hostedZoneId:s});Object.assign(m,P.resources)}return{resources:m,outputs:{identityLogicalId:g,configSetLogicalId:f}}}static InboundSmtpEndpoints={"us-east-1":"inbound-smtp.us-east-1.amazonaws.com","us-west-2":"inbound-smtp.us-west-2.amazonaws.com","eu-west-1":"inbound-smtp.eu-west-1.amazonaws.com"};static supportsInboundEmail(e){return e in N.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:n,environment:r,s3BucketArn:i,sesIdentityArn:s}=e,a=l({slug:n,environment:r,resourceType:"email-lambda-role"}),c=o(a),u=o(`${a}-policy`),d={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"],Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r}]}},m=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[i,`${i}/*`]}];if(s)m.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:s});let p={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${a}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:m},Roles:[v.Ref(c)]}};return{role:d,policy:p,roleLogicalId:c,policyLogicalId:u}}static createOutboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,domain:s,configurationSetName:a,timeout:c=30,memorySize:u=256}=e,d=l({slug:n,environment:r,resourceType:"outbound-email"}),m=o(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{DOMAIN:s,CONFIGURATION_SET:a||""}},Code:{ZipFile:N.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:m}}static createInboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:s,organizedPrefix:a="organized/",timeout:c=60,memorySize:u=512}=e,d=l({slug:n,environment:r,resourceType:"inbound-email"}),m=o(d),p=o(`${d}-permission`),g={Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:s,ORGANIZED_PREFIX:a}},Code:{ZipFile:N.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"InboundEmail"}]}},y={Type:"AWS::Lambda::Permission",Properties:{FunctionName:v.Ref(m),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:v.Ref("AWS::AccountId")}};return{function:g,permission:y,logicalId:m,permissionLogicalId:p}}static createEmailConversionLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:s,convertedPrefix:a="converted/",timeout:c=60,memorySize:u=512}=e,d=l({slug:n,environment:r,resourceType:"email-conversion"}),m=o(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:s,CONVERTED_PREFIX:a}},Code:{ZipFile:N.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:m}}static createEmailBucketNotification(e){let{lambdaArn:n,prefix:r="inbound/",suffix:i,events:s}=e,a=s??["s3:ObjectCreated:*"],c={};if(r||i){if(c.S3Key={Rules:[]},r)c.S3Key.Rules.push({Name:"prefix",Value:r});if(i)c.S3Key.Rules.push({Name:"suffix",Value:i})}return{notificationConfiguration:{LambdaConfigurations:[{Event:a[0],Function:n,Filter:Object.keys(c).length>0?c:void 0}]}}}static createS3LambdaPermission(e){let{slug:n,environment:r,lambdaLogicalId:i,s3BucketArn:s}=e,a=l({slug:n,environment:r,resourceType:"s3-lambda-permission"}),c=o(a);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:v.Ref(i),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:s}},logicalId:c}}static createEmailProcessingStack(e){let{slug:n,environment:r,domain:i,s3BucketName:s,s3BucketArn:a,configurationSetName:c,enableInbound:u=!0,enableConversion:d=!0}=e,m={},{role:p,policy:g,roleLogicalId:y,policyLogicalId:f}=N.createEmailLambdaRole({slug:n,environment:r,s3BucketArn:a,sesIdentityArn:`arn:aws:ses:*:*:identity/${i}`});m[y]=p,m[f]=g;let{function:h,logicalId:S}=N.createOutboundEmailLambda({slug:n,environment:r,roleArn:v.GetAtt(y,"Arn"),domain:i,configurationSetName:c});m[S]=h;let A={roleLogicalId:y,outboundLambdaLogicalId:S};if(u){let{function:R,permission:P,logicalId:C,permissionLogicalId:E}=N.createInboundEmailLambda({slug:n,environment:r,roleArn:v.GetAtt(y,"Arn"),s3BucketName:s});m[C]=R,m[E]=P;let{permission:D,logicalId:x}=N.createS3LambdaPermission({slug:n,environment:r,lambdaLogicalId:C,s3BucketArn:a});m[x]=D,A.inboundLambdaLogicalId=C}if(d){let{function:R,logicalId:P}=N.createEmailConversionLambda({slug:n,environment:r,roleArn:v.GetAtt(y,"Arn"),s3BucketName:s});m[P]=R,A.conversionLambdaLogicalId=P}return{resources:m,outputs:A}}static LambdaCode={outboundEmail:`
|
|
588
|
+
`}class lt{static createFileSystem(e){let{slug:n,environment:r,encrypted:i=!0,kmsKeyId:s,performanceMode:a="generalPurpose",throughputMode:c="bursting",provisionedThroughput:u,enableBackup:d=!0}=e,m=l({slug:n,environment:r,resourceType:"efs"}),p=o(m),g={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:i,PerformanceMode:a,ThroughputMode:c,FileSystemTags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(s)g.Properties.KmsKeyId=s;if(c==="provisioned"&&u)g.Properties.ProvisionedThroughputInMibps=u;if(d)g.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:g,logicalId:p}}static createMountTarget(e,n){let{slug:r,environment:i,subnetId:s,securityGroups:a,ipAddress:c}=n,u=l({slug:r,environment:i,resourceType:"efs-mt"}),d=o(`${u}-${s}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:v.Ref(e),SubnetId:s,SecurityGroups:a}};if(c)m.Properties.IpAddress=c;return{mountTarget:m,logicalId:d}}static createAccessPoint(e,n){let{slug:r,environment:i,path:s="/",uid:a="1000",gid:c="1000",permissions:u="755"}=n,d=l({slug:r,environment:i,resourceType:"efs-ap"}),m=o(`${d}-${s.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:v.Ref(e),PosixUser:{Uid:a,Gid:c},RootDirectory:{Path:s,CreationInfo:{OwnerUid:a,OwnerGid:c,Permissions:u}},AccessPointTags:[{Key:"Name",Value:`${d}-${s}`},{Key:"Environment",Value:i}]}},logicalId:m}}static setLifecyclePolicy(e,n){let{transitionToIA:r,transitionToPrimary:i=!1}=n;if(!e.Properties)e.Properties={};if(e.Properties.LifecyclePolicies=[],r){let s=`AFTER_${r}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:s})}if(i)e.Properties.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"});return e}static enableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"ENABLED"},e}static disableBackup(e){if(!e.Properties)e.Properties={};return e.Properties.BackupPolicy={Status:"DISABLED"},e}static setProvisionedThroughput(e,n){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="provisioned",e.Properties.ProvisionedThroughputInMibps=n,e}static setElasticThroughput(e){if(!e.Properties)e.Properties={};return e.Properties.ThroughputMode="elastic",e}static enableMaxIO(e){if(!e.Properties)e.Properties={};return e.Properties.PerformanceMode="maxIO",e}static createEfsSecurityGroup(e){let{slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:s=[],sourceCidrBlocks:a=[],description:c}=e,u=l({slug:n,environment:r,resourceType:"efs-sg"}),d=o(u),m=[];for(let g of s)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:g,Description:"NFS from security group"});for(let g of a)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:g,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:u,GroupDescription:c||`Security group for EFS mount targets - ${n} ${r}`,VpcId:i,SecurityGroupIngress:m,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}},logicalId:d}}static createMultiAzMountTargets(e,n){let{slug:r,environment:i,subnetIds:s,securityGroupId:a}=n,c=[],u=[];for(let d=0;d<s.length;d++){let m=s[d],p=l({slug:r,environment:i,resourceType:"efs-mt"}),g=o(`${p}-az${d+1}`),y={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:v.Ref(e),SubnetId:m,SecurityGroups:[a]}};c.push(y),u.push(g)}return{mountTargets:c,logicalIds:u}}static createCompleteFileSystem(e){let{slug:n,environment:r,vpcId:i,subnetIds:s,sourceSecurityGroupIds:a=[],encrypted:c=!0,performanceMode:u="generalPurpose",throughputMode:d="elastic",enableBackup:m=!0,transitionToIA:p}=e,g={},{fileSystem:y,logicalId:f}=lt.createFileSystem({slug:n,environment:r,encrypted:c,performanceMode:u,throughputMode:d,enableBackup:m});if(p)lt.setLifecyclePolicy(y,{transitionToIA:p,transitionToPrimary:!0});g[f]=y;let{securityGroup:h,logicalId:S}=lt.createEfsSecurityGroup({slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:a});g[S]=h;let{mountTargets:A,logicalIds:R}=lt.createMultiAzMountTargets(f,{slug:n,environment:r,subnetIds:s,securityGroupId:v.Ref(S)});for(let P=0;P<A.length;P++)g[R[P]]=A[P];return{resources:g,outputs:{fileSystemId:f,securityGroupId:S,mountTargetIds:R}}}}class N{static verifyDomain(e){let{domain:n,slug:r,environment:i,enableDkim:s=!0,dkimKeyLength:a="RSA_2048_BIT"}=e,c=l({slug:r,environment:i,resourceType:"ses-identity"}),u=o(`${c}-${n.replace(/\./g,"")}`),d={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:n,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(s)d.Properties.DkimSigningAttributes={NextSigningKeyLength:a};return{emailIdentity:d,logicalId:u}}static createDkimRecords(e,n,r){let i=[];for(let s=0;s<n.length;s++){let a=n[s],c=o(`dkim-${e.replace(/\./g,"")}-${s+1}`),u={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`${a}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${a}.dkim.amazonses.com`]}};i.push({record:u,logicalId:c})}return i}static createConfigurationSet(e){let{slug:n,environment:r,name:i,reputationMetrics:s=!0,sendingEnabled:a=!0,suppressBounces:c=!0,suppressComplaints:u=!0}=e,d=i||l({slug:n,environment:r,resourceType:"ses-config"}),m=o(d),p=[];if(c)p.push("BOUNCE");if(u)p.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:d,ReputationOptions:{ReputationMetricsEnabled:s},SendingOptions:{SendingEnabled:a},SuppressionOptions:{SuppressedReasons:p}}},logicalId:m}}static createReceiptRuleSet(e){let{slug:n,environment:r,name:i}=e,s=i||l({slug:n,environment:r,resourceType:"ses-ruleset"}),a=o(s);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:s}},logicalId:a}}static createReceiptRule(e,n){let{slug:r,environment:i,ruleSetName:s,recipients:a,enabled:c=!0,scanEnabled:u=!0,tlsPolicy:d="Require",s3Action:m,lambdaAction:p,snsAction:g}=n,y=l({slug:r,environment:i,resourceType:"ses-rule"}),f=o(y),h=[];if(m)h.push({S3Action:{BucketName:m.bucketName,ObjectKeyPrefix:m.prefix,KmsKeyArn:m.kmsKeyArn}});if(p)h.push({LambdaAction:{FunctionArn:p.functionArn,InvocationType:p.invocationType||"Event"}});if(g)h.push({SNSAction:{TopicArn:g.topicArn,Encoding:g.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:s,Rule:{Name:y,Enabled:c,ScanEnabled:u,TlsPolicy:d,Recipients:a,Actions:h.length>0?h:void 0}}},logicalId:f}}static createMxRecord(e,n,r){let i=o(`mx-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${r}.amazonaws.com`]}},logicalId:i}}static createVerificationRecord(e,n,r){let i=o(`verification-${e.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`_amazonses.${e}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${n}"`]}},logicalId:i}}static getSmtpEndpoint(e){return`email-smtp.${e}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(e,n,r){let{includeDomains:i=[],softFail:s=!1}=r||{},a=o(`spf-${e.replace(/\./g,"")}`),c="v=spf1 include:amazonses.com";for(let d of i)c+=` include:${d}`;return c+=s?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${c}"`]}},logicalId:a}}static createDmarcRecord(e,n,r){let{policy:i="none",subdomainPolicy:s,percentage:a=100,reportingEmail:c,forensicEmail:u}=r||{},d=o(`dmarc-${e.replace(/\./g,"")}`),m=`v=DMARC1; p=${i}; pct=${a}`;if(s)m+=`; sp=${s}`;if(c)m+=`; rua=mailto:${c}`;if(u)m+=`; ruf=mailto:${u}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:`_dmarc.${e}`,Type:"TXT",TTL:300,ResourceRecords:[`"${m}"`]}},logicalId:d}}static createInboundEmailSetup(e){let{slug:n,environment:r,domain:i,s3BucketName:s,s3KeyPrefix:a="inbound/",region:c,hostedZoneId:u,lambdaFunctionArn:d,snsTopicArn:m}=e,p={},{ruleSet:g,logicalId:y}=N.createReceiptRuleSet({slug:n,environment:r});p[y]=g;let{receiptRule:f,logicalId:h}=N.createReceiptRule(y,{slug:n,environment:r,ruleSetName:g.Properties.RuleSetName||`${n}-${r}-receipt-rule-set`,recipients:[i],s3Action:{bucketName:s,prefix:a},lambdaAction:d?{functionArn:d,invocationType:"Event"}:void 0,snsAction:m?{topicArn:m}:void 0});p[h]=f;let{record:S,logicalId:A}=N.createMxRecord(i,u,c);return p[A]=S,{resources:p,outputs:{ruleSetLogicalId:y,ruleLogicalId:h,mxRecordLogicalId:A}}}static createCompleteDomainSetup(e){let{slug:n,environment:r,domain:i,hostedZoneId:s,region:a,enableInbound:c=!1,inboundS3Bucket:u,dmarcReportingEmail:d}=e,m={},{emailIdentity:p,logicalId:g}=N.verifyDomain({domain:i,slug:n,environment:r});m[g]=p;let{configurationSet:y,logicalId:f}=N.createConfigurationSet({slug:n,environment:r});m[f]=y;let{record:h,logicalId:S}=N.createSpfRecord(i,s);m[S]=h;let{record:A,logicalId:R}=N.createDmarcRecord(i,s,{policy:"none",reportingEmail:d||`dmarc-reports@${i}`});if(m[R]=A,c&&u){let P=N.createInboundEmailSetup({slug:n,environment:r,domain:i,s3BucketName:u,region:a,hostedZoneId:s});Object.assign(m,P.resources)}return{resources:m,outputs:{identityLogicalId:g,configSetLogicalId:f}}}static InboundSmtpEndpoints={"us-east-1":"inbound-smtp.us-east-1.amazonaws.com","us-west-2":"inbound-smtp.us-west-2.amazonaws.com","eu-west-1":"inbound-smtp.eu-west-1.amazonaws.com"};static supportsInboundEmail(e){return e in N.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:n,environment:r,s3BucketArn:i,sesIdentityArn:s}=e,a=l({slug:n,environment:r,resourceType:"email-lambda-role"}),c=o(a),u=o(`${a}-policy`),d={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"],Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r}]}},m=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[i,`${i}/*`]}];if(s)m.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:s});let p={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${a}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:m},Roles:[v.Ref(c)]}};return{role:d,policy:p,roleLogicalId:c,policyLogicalId:u}}static createOutboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,domain:s,configurationSetName:a,timeout:c=30,memorySize:u=256}=e,d=l({slug:n,environment:r,resourceType:"outbound-email"}),m=o(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{DOMAIN:s,CONFIGURATION_SET:a||""}},Code:{ZipFile:N.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:m}}static createInboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:s,organizedPrefix:a="organized/",timeout:c=60,memorySize:u=512}=e,d=l({slug:n,environment:r,resourceType:"inbound-email"}),m=o(d),p=o(`${d}-permission`),g={Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:s,ORGANIZED_PREFIX:a}},Code:{ZipFile:N.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"InboundEmail"}]}},y={Type:"AWS::Lambda::Permission",Properties:{FunctionName:v.Ref(m),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:v.Ref("AWS::AccountId")}};return{function:g,permission:y,logicalId:m,permissionLogicalId:p}}static createEmailConversionLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:s,convertedPrefix:a="converted/",timeout:c=60,memorySize:u=512}=e,d=l({slug:n,environment:r,resourceType:"email-conversion"}),m=o(d);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:d,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c,MemorySize:u,Environment:{Variables:{S3_BUCKET:s,CONVERTED_PREFIX:a}},Code:{ZipFile:N.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:m}}static createEmailBucketNotification(e){let{lambdaArn:n,prefix:r="inbound/",suffix:i,events:s}=e,a=s??["s3:ObjectCreated:*"],c={};if(r||i){if(c.S3Key={Rules:[]},r)c.S3Key.Rules.push({Name:"prefix",Value:r});if(i)c.S3Key.Rules.push({Name:"suffix",Value:i})}return{notificationConfiguration:{LambdaConfigurations:[{Event:a[0],Function:n,Filter:Object.keys(c).length>0?c:void 0}]}}}static createS3LambdaPermission(e){let{slug:n,environment:r,lambdaLogicalId:i,s3BucketArn:s}=e,a=l({slug:n,environment:r,resourceType:"s3-lambda-permission"}),c=o(a);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:v.Ref(i),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:s}},logicalId:c}}static createEmailProcessingStack(e){let{slug:n,environment:r,domain:i,s3BucketName:s,s3BucketArn:a,configurationSetName:c,enableInbound:u=!0,enableConversion:d=!0}=e,m={},{role:p,policy:g,roleLogicalId:y,policyLogicalId:f}=N.createEmailLambdaRole({slug:n,environment:r,s3BucketArn:a,sesIdentityArn:`arn:aws:ses:*:*:identity/${i}`});m[y]=p,m[f]=g;let{function:h,logicalId:S}=N.createOutboundEmailLambda({slug:n,environment:r,roleArn:v.GetAtt(y,"Arn"),domain:i,configurationSetName:c});m[S]=h;let A={roleLogicalId:y,outboundLambdaLogicalId:S};if(u){let{function:R,permission:P,logicalId:C,permissionLogicalId:E}=N.createInboundEmailLambda({slug:n,environment:r,roleArn:v.GetAtt(y,"Arn"),s3BucketName:s});m[C]=R,m[E]=P;let{permission:D,logicalId:x}=N.createS3LambdaPermission({slug:n,environment:r,lambdaLogicalId:C,s3BucketArn:a});m[x]=D,A.inboundLambdaLogicalId=C}if(d){let{function:R,logicalId:P}=N.createEmailConversionLambda({slug:n,environment:r,roleArn:v.GetAtt(y,"Arn"),s3BucketName:s});m[P]=R,A.conversionLambdaLogicalId=P}return{resources:m,outputs:A}}static LambdaCode={outboundEmail:`
|
|
589
589
|
const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
|
|
590
590
|
const ses = new SESClient({});
|
|
591
591
|
|
|
@@ -1131,7 +1131,7 @@ else if (encoding === 'quoted-printable') {
|
|
|
1131
1131
|
|
|
1132
1132
|
return content;
|
|
1133
1133
|
}
|
|
1134
|
-
`}}var
|
|
1134
|
+
`}}var bt=`
|
|
1135
1135
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1136
1136
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1137
1137
|
|
|
@@ -1238,7 +1238,7 @@ catch (error) {
|
|
|
1238
1238
|
};
|
|
1239
1239
|
}
|
|
1240
1240
|
};
|
|
1241
|
-
`,
|
|
1241
|
+
`,Xr=`
|
|
1242
1242
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1243
1243
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1244
1244
|
|
|
@@ -1345,7 +1345,7 @@ catch (error) {
|
|
|
1345
1345
|
};
|
|
1346
1346
|
}
|
|
1347
1347
|
};
|
|
1348
|
-
`;var
|
|
1348
|
+
`;var cn=`
|
|
1349
1349
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1350
1350
|
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1351
1351
|
|
|
@@ -1452,7 +1452,7 @@ catch (error) {
|
|
|
1452
1452
|
};
|
|
1453
1453
|
}
|
|
1454
1454
|
};
|
|
1455
|
-
`;var
|
|
1455
|
+
`;var ln=`
|
|
1456
1456
|
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
1457
1457
|
const { TranscribeClient, StartTranscriptionJobCommand, GetTranscriptionJobCommand } = require('@aws-sdk/client-transcribe');
|
|
1458
1458
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
@@ -1623,7 +1623,7 @@ catch (error) {
|
|
|
1623
1623
|
|
|
1624
1624
|
return { statusCode: 200, body: 'OK' };
|
|
1625
1625
|
};
|
|
1626
|
-
`;class kt{static LambdaCode={incomingCall:yt,voicemail:sn,missedCall:rn};static createConnectInstance(e){let{slug:n,environment:r,instanceAlias:i,inboundCallsEnabled:s=!0,outboundCallsEnabled:a=!0}=e;return{[`${n}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:i,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:s,OutboundCalls:a,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((n)=>({Day:n.day,StartTime:{Hours:n.startHour,Minutes:n.startMinute},EndTime:{Hours:n.endHour,Minutes:n.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 n={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(n)}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:kt.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:kt.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:kt.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 n={},r={};Object.assign(n,kt.createPhoneLambdaRole({slug:e.slug})),Object.assign(n,kt.createCallLogTable({slug:e.slug})),n[`${e.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-phone-notifications`}},n[`${e.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let i={"Fn::GetAtt":[`${e.slug}PhoneLambdaRole`,"Arn"]},s={Ref:`${e.slug}PhoneNotificationTopic`},a={Ref:`${e.slug}CallLogTable`},c={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(n,kt.createIncomingCallLambda({slug:e.slug,roleArn:i,notificationTopicArn:s,callLogTable:a,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(n,kt.createVoicemailLambda({slug:e.slug,roleArn:i,voicemailBucket:c,notificationTopicArn:s,callLogTable:a,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(n,kt.createMissedCallLambda({slug:e.slug,roleArn:i,notificationTopicArn:s,callLogTable:a,webhookUrl:e.webhookUrl})),r[`${e.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${e.slug}PhoneNotificationTopic`}},r[`${e.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${e.slug}CallLogTable`}},r[`${e.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${e.slug}VoicemailBucket`}},{resources:n,outputs:r}}}class ye{static createQueue(e){let{slug:n,environment:r,name:i,delaySeconds:s=0,visibilityTimeout:a=30,messageRetentionPeriod:c=345600,maxMessageSize:u=262144,receiveMessageWaitTime:d=0,fifo:m=!1,contentBasedDeduplication:p=!1,encrypted:g=!0,kmsKeyId:y}=e,f=i||l({slug:n,environment:r,resourceType:"queue"}),h=m?`${f}.fifo`:f,S=o(f),A={Type:"AWS::SQS::Queue",Properties:{QueueName:h,DelaySeconds:s,MaximumMessageSize:u,MessageRetentionPeriod:c,ReceiveMessageWaitTimeSeconds:d,VisibilityTimeout:a,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};if(m)A.Properties.FifoQueue=!0,A.Properties.ContentBasedDeduplication=p;if(g)if(y)A.Properties.KmsMasterKeyId=y;else A.Properties.SqsManagedSseEnabled=!0;return{queue:A,logicalId:S}}static createDeadLetterQueue(e,n){let{slug:r,environment:i,maxReceiveCount:s=3}=n,a=l({slug:r,environment:i,resourceType:"dlq"}),c=o(a),u={Type:"AWS::SQS::Queue",Properties:{QueueName:a,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i},{Key:"Type",Value:"DeadLetterQueue"}]}},d={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:v.GetAtt(c,"Arn"),maxReceiveCount:s}}};return{deadLetterQueue:u,updatedSourceQueue:d,deadLetterLogicalId:c}}static createSchedule(e,n){let{slug:r,environment:i,name:s,description:a,enabled:c=!0}=n,u=s||l({slug:r,environment:i,resourceType:"schedule"}),d=o(u);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:u,Description:a,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[]}},logicalId:d}}static scheduleEcsTask(e,n,r){let{slug:i,environment:s,name:a,description:c,enabled:u=!0,taskDefinitionArn:d,clusterArn:m,subnets:p,securityGroups:g=[],assignPublicIp:y=!1,taskCount:f=1,containerOverrides:h}=r,S=a||l({slug:i,environment:s,resourceType:"ecs-schedule"}),A=o(S),P={Id:"1",Arn:m,RoleArn:n,EcsParameters:{TaskDefinitionArn:d,TaskCount:f,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:p,SecurityGroups:g,AssignPublicIp:y?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(h&&h.length>0)P.Input=JSON.stringify({containerOverrides:h});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:S,Description:c||`Scheduled ECS task: ${d}`,ScheduleExpression:e,State:u?"ENABLED":"DISABLED",Targets:[P]}},logicalId:A}}static scheduleLambda(e,n){let{slug:r,environment:i,name:s,description:a,enabled:c=!0,functionArn:u,input:d}=n,m=s||l({slug:r,environment:i,resourceType:"lambda-schedule"}),p=o(m),g={Id:"1",Arn:u};if(d)g.Input=JSON.stringify(d);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:a||`Scheduled Lambda: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static scheduleSqsMessage(e,n){let{slug:r,environment:i,name:s,description:a,enabled:c=!0,queueArn:u,messageGroupId:d}=n,m=s||l({slug:r,environment:i,resourceType:"sqs-schedule"}),p=o(m),g={Id:"1",Arn:u};if(d)g.SqsParameters={MessageGroupId:d};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:a||`Scheduled SQS message: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static addTarget(e,n){if(!e.Properties.Targets)e.Properties.Targets=[];let r={Id:n.id,Arn:n.arn};if(n.roleArn)r.RoleArn=n.roleArn;if(n.input)r.Input=JSON.stringify(n.input);return e.Properties.Targets.push(r),e}static toCronExpression(e){if(e.startsWith("cron(")||e.startsWith("rate("))return e;return`cron(${e})`}static rateExpression(e,n){return`rate(${e} ${n})`}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 n=e.toLowerCase().trim(),r=n.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(r){let m=parseInt(r[1],10),p=r[2].toLowerCase(),g=p.endsWith("s")&&m===1?p.slice(0,-1):p,y=!p.endsWith("s")&&m>1?`${p}s`:p;return`rate(${m} ${m===1?g:y})`}let i=n.match(/^every\s+(minute|hour|day)$/i);if(i)return`rate(1 ${i[1]})`;let s={"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(s[n])return s[n];let a=n.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(a){let m=parseInt(a[1],10),p=a[2]?.toLowerCase();if(p==="pm"&&m!==12)m+=12;else if(p==="am"&&m===12)m=0;return`cron(0 ${m} * * ? *)`}let c=n.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(c){let m=parseInt(c[1],10);return`cron(${parseInt(c[2],10)} ${m} * * ? *)`}let u={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},d=n.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(d)return`cron(0 0 ? * ${u[d[1].toLowerCase()]} *)`;return ye.toCronExpression(e)}static JobConfig={create:(e)=>{let{name:n,handler:r,retries:i=3,backoff:s="exponential",backoffDelay:a=1000,maxDelay:c=30000,timeout:u=60000,jitter:d=!0}=e;return{name:n,handler:r,retries:i,backoff:s,backoffDelay:a,maxDelay:c,timeout:u,jitter:d}},calculateDelay:(e,n)=>{let{backoff:r,backoffDelay:i,maxDelay:s,jitter:a}=n,c;switch(r){case"linear":c=i*e;break;case"exponential":c=i*2**(e-1);break;case"fixed":default:c=i}if(c=Math.min(c,s||Number.MAX_SAFE_INTEGER),a){let u=c*0.25*Math.random();c+=u}return Math.floor(c)},presets:{fastRetry:{retries:5,backoff:"exponential",backoffDelay:100,maxDelay:5000,jitter:!0},standard:{retries:3,backoff:"exponential",backoffDelay:1000,maxDelay:30000,jitter:!0},longRunning:{retries:2,backoff:"exponential",backoffDelay:5000,maxDelay:60000,timeout:300000,jitter:!0},critical:{retries:10,backoff:"exponential",backoffDelay:500,maxDelay:60000,jitter:!0},noRetry:{retries:0,backoff:"fixed",backoffDelay:0,maxDelay:0,jitter:!1}}};static createJobContainerOverride(e){let{containerName:n,jobClass:r,jobData:i,environment:s={}}=e,a=[{name:"JOB_CLASS",value:r}];if(i)a.push({name:"JOB_DATA",value:JSON.stringify(i)});for(let[c,u]of Object.entries(s))a.push({name:c,value:u});return{name:n,command:["bun","run","app/Jobs/runner.ts"],environment:a}}static createScheduledJob(e){let{slug:n,environment:r,schedule:i,jobClass:s,jobData:a,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m=[],roleArn:p,containerName:g="app"}=e,y=ye.rateStringToExpression(i),f=ye.createJobContainerOverride({containerName:g,jobClass:s,jobData:a});return ye.scheduleEcsTask(y,p,{slug:n,environment:r,name:`${n}-${s.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${s}`,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m,containerOverrides:[f]})}static QueuePresets={highThroughput:(e,n)=>ye.createQueue({slug:e,environment:n,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,n)=>ye.createQueue({slug:e,environment:n,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,n)=>ye.createQueue({slug:e,environment:n,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,n,r=60)=>ye.createQueue({slug:e,environment:n,delaySeconds:r})}}class Qt{static async discoverJobs(e){let{projectRoot:n,jobsPath:r="app/Jobs"}=e,i=`${n}/${r}`,s=[];try{let a=await import("node:fs"),c=await import("node:path");if(!a.existsSync(i))return[];let u=a.readdirSync(i).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_")&&d!=="runner.ts");for(let d of u){let m=c.join(i,d),p=d.replace(".ts",""),g=a.readFileSync(m,"utf-8"),y=Qt.parseJobMetadata(g,p,m);if(y)s.push(y)}}catch{return[]}return s}static parseJobMetadata(e,n,r){let i=e.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/schedule:\s*['"`]([^'"`]+)['"`]/),s=e.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||e.match(/enabled:\s*(true|false)/),a=e.match(/export\s+const\s+retries\s*=\s*(\d+)/)||e.match(/retries:\s*(\d+)/),c=e.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||e.match(/timeout:\s*(\d+)/),u=e.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||e.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),d=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;return{name:n,path:r,schedule:i?.[1],handler:`${n}.handle`,enabled:s?.[1]!=="false",retries:a?parseInt(a[1],10):void 0,backoff:u?.[1],timeout:c?parseInt(c[1],10):void 0,description:d?.[1]}}static async discoverActions(e){let{projectRoot:n,actionsPath:r="app/Actions"}=e,i=`${n}/${r}`,s=[];try{let a=await import("node:fs"),c=await import("node:path");if(!a.existsSync(i))return[];let u=a.readdirSync(i).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_"));for(let d of u){let m=c.join(i,d),p=d.replace(".ts",""),g=a.readFileSync(m,"utf-8"),y=Qt.parseActionMetadata(g,p,m);if(y)s.push(y)}}catch{return[]}return s}static parseActionMetadata(e,n,r){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let s=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:n,path:r,handler:`${n}.handle`,description:s?.[1]}}static generateScheduledJobResources(e){let{slug:n,environment:r,jobs:i,taskDefinitionArn:s,clusterArn:a,subnets:c,securityGroups:u=[],roleArn:d,containerName:m="app"}=e,p={},g=0;for(let y of i){if(!y.schedule||!y.enabled)continue;let{rule:f,logicalId:h}=ye.createScheduledJob({slug:n,environment:r,schedule:y.schedule,jobClass:y.name,taskDefinitionArn:s,clusterArn:a,subnets:c,securityGroups:u,roleArn:d,containerName:m});p[h]=f,g++}return{rules:p,count:g}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1626
|
+
`;class xt{static LambdaCode={incomingCall:bt,voicemail:ln,missedCall:cn};static createConnectInstance(e){let{slug:n,environment:r,instanceAlias:i,inboundCallsEnabled:s=!0,outboundCallsEnabled:a=!0}=e;return{[`${n}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:i,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:s,OutboundCalls:a,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((n)=>({Day:n.day,StartTime:{Hours:n.startHour,Minutes:n.startMinute},EndTime:{Hours:n.endHour,Minutes:n.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 n={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(n)}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:xt.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:xt.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:xt.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 n={},r={};Object.assign(n,xt.createPhoneLambdaRole({slug:e.slug})),Object.assign(n,xt.createCallLogTable({slug:e.slug})),n[`${e.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${e.slug}-phone-notifications`}},n[`${e.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${e.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let i={"Fn::GetAtt":[`${e.slug}PhoneLambdaRole`,"Arn"]},s={Ref:`${e.slug}PhoneNotificationTopic`},a={Ref:`${e.slug}CallLogTable`},c={Ref:`${e.slug}VoicemailBucket`};if(Object.assign(n,xt.createIncomingCallLambda({slug:e.slug,roleArn:i,notificationTopicArn:s,callLogTable:a,webhookUrl:e.webhookUrl})),e.voicemailEnabled!==!1)Object.assign(n,xt.createVoicemailLambda({slug:e.slug,roleArn:i,voicemailBucket:c,notificationTopicArn:s,callLogTable:a,transcriptionEnabled:e.transcriptionEnabled}));return Object.assign(n,xt.createMissedCallLambda({slug:e.slug,roleArn:i,notificationTopicArn:s,callLogTable:a,webhookUrl:e.webhookUrl})),r[`${e.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${e.slug}PhoneNotificationTopic`}},r[`${e.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${e.slug}CallLogTable`}},r[`${e.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${e.slug}VoicemailBucket`}},{resources:n,outputs:r}}}class be{static createQueue(e){let{slug:n,environment:r,name:i,delaySeconds:s=0,visibilityTimeout:a=30,messageRetentionPeriod:c=345600,maxMessageSize:u=262144,receiveMessageWaitTime:d=0,fifo:m=!1,contentBasedDeduplication:p=!1,encrypted:g=!0,kmsKeyId:y}=e,f=i||l({slug:n,environment:r,resourceType:"queue"}),h=m?`${f}.fifo`:f,S=o(f),A={Type:"AWS::SQS::Queue",Properties:{QueueName:h,DelaySeconds:s,MaximumMessageSize:u,MessageRetentionPeriod:c,ReceiveMessageWaitTimeSeconds:d,VisibilityTimeout:a,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r}]}};if(m)A.Properties.FifoQueue=!0,A.Properties.ContentBasedDeduplication=p;if(g)if(y)A.Properties.KmsMasterKeyId=y;else A.Properties.SqsManagedSseEnabled=!0;return{queue:A,logicalId:S}}static createDeadLetterQueue(e,n){let{slug:r,environment:i,maxReceiveCount:s=3}=n,a=l({slug:r,environment:i,resourceType:"dlq"}),c=o(a),u={Type:"AWS::SQS::Queue",Properties:{QueueName:a,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i},{Key:"Type",Value:"DeadLetterQueue"}]}},d={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:v.GetAtt(c,"Arn"),maxReceiveCount:s}}};return{deadLetterQueue:u,updatedSourceQueue:d,deadLetterLogicalId:c}}static createSchedule(e,n){let{slug:r,environment:i,name:s,description:a,enabled:c=!0}=n,u=s||l({slug:r,environment:i,resourceType:"schedule"}),d=o(u);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:u,Description:a,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[]}},logicalId:d}}static scheduleEcsTask(e,n,r){let{slug:i,environment:s,name:a,description:c,enabled:u=!0,taskDefinitionArn:d,clusterArn:m,subnets:p,securityGroups:g=[],assignPublicIp:y=!1,taskCount:f=1,containerOverrides:h}=r,S=a||l({slug:i,environment:s,resourceType:"ecs-schedule"}),A=o(S),P={Id:"1",Arn:m,RoleArn:n,EcsParameters:{TaskDefinitionArn:d,TaskCount:f,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:p,SecurityGroups:g,AssignPublicIp:y?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(h&&h.length>0)P.Input=JSON.stringify({containerOverrides:h});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:S,Description:c||`Scheduled ECS task: ${d}`,ScheduleExpression:e,State:u?"ENABLED":"DISABLED",Targets:[P]}},logicalId:A}}static scheduleLambda(e,n){let{slug:r,environment:i,name:s,description:a,enabled:c=!0,functionArn:u,input:d}=n,m=s||l({slug:r,environment:i,resourceType:"lambda-schedule"}),p=o(m),g={Id:"1",Arn:u};if(d)g.Input=JSON.stringify(d);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:a||`Scheduled Lambda: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static scheduleSqsMessage(e,n){let{slug:r,environment:i,name:s,description:a,enabled:c=!0,queueArn:u,messageGroupId:d}=n,m=s||l({slug:r,environment:i,resourceType:"sqs-schedule"}),p=o(m),g={Id:"1",Arn:u};if(d)g.SqsParameters={MessageGroupId:d};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:m,Description:a||`Scheduled SQS message: ${u}`,ScheduleExpression:e,State:c?"ENABLED":"DISABLED",Targets:[g]}},logicalId:p}}static addTarget(e,n){if(!e.Properties.Targets)e.Properties.Targets=[];let r={Id:n.id,Arn:n.arn};if(n.roleArn)r.RoleArn=n.roleArn;if(n.input)r.Input=JSON.stringify(n.input);return e.Properties.Targets.push(r),e}static toCronExpression(e){if(e.startsWith("cron(")||e.startsWith("rate("))return e;return`cron(${e})`}static rateExpression(e,n){return`rate(${e} ${n})`}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 n=e.toLowerCase().trim(),r=n.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(r){let m=parseInt(r[1],10),p=r[2].toLowerCase(),g=p.endsWith("s")&&m===1?p.slice(0,-1):p,y=!p.endsWith("s")&&m>1?`${p}s`:p;return`rate(${m} ${m===1?g:y})`}let i=n.match(/^every\s+(minute|hour|day)$/i);if(i)return`rate(1 ${i[1]})`;let s={"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(s[n])return s[n];let a=n.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(a){let m=parseInt(a[1],10),p=a[2]?.toLowerCase();if(p==="pm"&&m!==12)m+=12;else if(p==="am"&&m===12)m=0;return`cron(0 ${m} * * ? *)`}let c=n.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(c){let m=parseInt(c[1],10);return`cron(${parseInt(c[2],10)} ${m} * * ? *)`}let u={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},d=n.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(d)return`cron(0 0 ? * ${u[d[1].toLowerCase()]} *)`;return be.toCronExpression(e)}static JobConfig={create:(e)=>{let{name:n,handler:r,retries:i=3,backoff:s="exponential",backoffDelay:a=1000,maxDelay:c=30000,timeout:u=60000,jitter:d=!0}=e;return{name:n,handler:r,retries:i,backoff:s,backoffDelay:a,maxDelay:c,timeout:u,jitter:d}},calculateDelay:(e,n)=>{let{backoff:r,backoffDelay:i,maxDelay:s,jitter:a}=n,c;switch(r){case"linear":c=i*e;break;case"exponential":c=i*2**(e-1);break;case"fixed":default:c=i}if(c=Math.min(c,s||Number.MAX_SAFE_INTEGER),a){let u=c*0.25*Math.random();c+=u}return Math.floor(c)},presets:{fastRetry:{retries:5,backoff:"exponential",backoffDelay:100,maxDelay:5000,jitter:!0},standard:{retries:3,backoff:"exponential",backoffDelay:1000,maxDelay:30000,jitter:!0},longRunning:{retries:2,backoff:"exponential",backoffDelay:5000,maxDelay:60000,timeout:300000,jitter:!0},critical:{retries:10,backoff:"exponential",backoffDelay:500,maxDelay:60000,jitter:!0},noRetry:{retries:0,backoff:"fixed",backoffDelay:0,maxDelay:0,jitter:!1}}};static createJobContainerOverride(e){let{containerName:n,jobClass:r,jobData:i,environment:s={}}=e,a=[{name:"JOB_CLASS",value:r}];if(i)a.push({name:"JOB_DATA",value:JSON.stringify(i)});for(let[c,u]of Object.entries(s))a.push({name:c,value:u});return{name:n,command:["bun","run","app/Jobs/runner.ts"],environment:a}}static createScheduledJob(e){let{slug:n,environment:r,schedule:i,jobClass:s,jobData:a,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m=[],roleArn:p,containerName:g="app"}=e,y=be.rateStringToExpression(i),f=be.createJobContainerOverride({containerName:g,jobClass:s,jobData:a});return be.scheduleEcsTask(y,p,{slug:n,environment:r,name:`${n}-${s.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${s}`,taskDefinitionArn:c,clusterArn:u,subnets:d,securityGroups:m,containerOverrides:[f]})}static QueuePresets={highThroughput:(e,n)=>be.createQueue({slug:e,environment:n,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(e,n)=>be.createQueue({slug:e,environment:n,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(e,n)=>be.createQueue({slug:e,environment:n,fifo:!0,contentBasedDeduplication:!0}),delayed:(e,n,r=60)=>be.createQueue({slug:e,environment:n,delaySeconds:r})}}class Zt{static async discoverJobs(e){let{projectRoot:n,jobsPath:r="app/Jobs"}=e,i=`${n}/${r}`,s=[];try{let a=await import("node:fs"),c=await import("node:path");if(!a.existsSync(i))return[];let u=a.readdirSync(i).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_")&&d!=="runner.ts");for(let d of u){let m=c.join(i,d),p=d.replace(".ts",""),g=a.readFileSync(m,"utf-8"),y=Zt.parseJobMetadata(g,p,m);if(y)s.push(y)}}catch{return[]}return s}static parseJobMetadata(e,n,r){let i=e.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/schedule:\s*['"`]([^'"`]+)['"`]/),s=e.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||e.match(/enabled:\s*(true|false)/),a=e.match(/export\s+const\s+retries\s*=\s*(\d+)/)||e.match(/retries:\s*(\d+)/),c=e.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||e.match(/timeout:\s*(\d+)/),u=e.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||e.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),d=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;return{name:n,path:r,schedule:i?.[1],handler:`${n}.handle`,enabled:s?.[1]!=="false",retries:a?parseInt(a[1],10):void 0,backoff:u?.[1],timeout:c?parseInt(c[1],10):void 0,description:d?.[1]}}static async discoverActions(e){let{projectRoot:n,actionsPath:r="app/Actions"}=e,i=`${n}/${r}`,s=[];try{let a=await import("node:fs"),c=await import("node:path");if(!a.existsSync(i))return[];let u=a.readdirSync(i).filter((d)=>d.endsWith(".ts")&&!d.startsWith("_"));for(let d of u){let m=c.join(i,d),p=d.replace(".ts",""),g=a.readFileSync(m,"utf-8"),y=Zt.parseActionMetadata(g,p,m);if(y)s.push(y)}}catch{return[]}return s}static parseActionMetadata(e,n,r){if(!(e.includes("export async function handle")||e.includes("export function handle")||e.includes("export default")))return null;let s=e.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||e.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:n,path:r,handler:`${n}.handle`,description:s?.[1]}}static generateScheduledJobResources(e){let{slug:n,environment:r,jobs:i,taskDefinitionArn:s,clusterArn:a,subnets:c,securityGroups:u=[],roleArn:d,containerName:m="app"}=e,p={},g=0;for(let y of i){if(!y.schedule||!y.enabled)continue;let{rule:f,logicalId:h}=be.createScheduledJob({slug:n,environment:r,schedule:y.schedule,jobClass:y.name,taskDefinitionArn:s,clusterArn:a,subnets:c,securityGroups:u,roleArn:d,containerName:m});p[h]=f,g++}return{rules:p,count:g}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
|
|
1627
1627
|
/**
|
|
1628
1628
|
* Job Runner Script
|
|
1629
1629
|
* This script is invoked by ECS scheduled tasks to run jobs
|
|
@@ -1668,7 +1668,7 @@ catch (error) {
|
|
|
1668
1668
|
}
|
|
1669
1669
|
|
|
1670
1670
|
run()
|
|
1671
|
-
`}static async generateJobManifest(e){let n=await
|
|
1671
|
+
`}static async generateJobManifest(e){let n=await Zt.discoverJobs(e),r=n.filter((i)=>i.schedule&&i.enabled);return{jobs:n,scheduledCount:r.length,totalCount:n.length}}}var Hm={loadJobs:Zt.discoverJobs,loadActions:Zt.discoverActions,generateScheduledJobs:Zt.generateScheduledJobResources,generateRunner:Zt.generateJobRunnerScript,paths:{jobs:"app/Jobs",actions:"app/Actions",runner:"app/Jobs/runner.ts"}};var un=`
|
|
1672
1672
|
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1673
1673
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1674
1674
|
|
|
@@ -1791,7 +1791,7 @@ catch (error) {
|
|
|
1791
1791
|
|
|
1792
1792
|
return { statusCode: 200, body: 'OK' };
|
|
1793
1793
|
};
|
|
1794
|
-
`;var
|
|
1794
|
+
`;var dn=`
|
|
1795
1795
|
const { DynamoDBClient, PutItemCommand, DeleteItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
1796
1796
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1797
1797
|
|
|
@@ -1943,7 +1943,7 @@ catch (error) {
|
|
|
1943
1943
|
|
|
1944
1944
|
return { statusCode: 200, body: 'OK' };
|
|
1945
1945
|
};
|
|
1946
|
-
`;var
|
|
1946
|
+
`;var St=`
|
|
1947
1947
|
const { PinpointClient, SendMessagesCommand } = require('@aws-sdk/client-pinpoint');
|
|
1948
1948
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
1949
1949
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
@@ -2107,7 +2107,7 @@ function resolveTemplate(template, data) {
|
|
|
2107
2107
|
}
|
|
2108
2108
|
return result;
|
|
2109
2109
|
}
|
|
2110
|
-
`,
|
|
2110
|
+
`,ei=`
|
|
2111
2111
|
const { PinpointClient, SendMessagesCommand } = require('@aws-sdk/client-pinpoint');
|
|
2112
2112
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
2113
2113
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
@@ -2271,14 +2271,14 @@ function resolveTemplate(template, data) {
|
|
|
2271
2271
|
}
|
|
2272
2272
|
return result;
|
|
2273
2273
|
}
|
|
2274
|
-
`;class Re{static LambdaCode={send:ft,receive:on,deliveryStatus:an};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let n={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)n.SenderId=e.senderId;if(e.shortCode)n.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:n}}}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:Re.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:Re.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:Re.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 n={},r={};Object.assign(n,Re.createPinpointApp({slug:e.slug})),Object.assign(n,Re.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(n,Re.createSmsLambdaRole({slug:e.slug})),Object.assign(n,Re.createMessageLogTable({slug:e.slug})),Object.assign(n,Re.createOptOutTable({slug:e.slug})),Object.assign(n,Re.createNotificationTopic({slug:e.slug}));let i={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},s={Ref:`${e.slug}PinpointApp`},a={Ref:`${e.slug}SmsMessageLogTable`},c={Ref:`${e.slug}SmsOptOutTable`},u={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(n,Re.createSendLambda({slug:e.slug,roleArn:i,pinpointAppId:s,messageLogTable:a,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(n,Re.createReceiveLambda({slug:e.slug,roleArn:i,optOutTable:c,messageLogTable:a,notificationTopicArn:u,webhookUrl:e.webhookUrl}));return Object.assign(n,Re.createDeliveryStatusLambda({slug:e.slug,roleArn:i,messageLogTable:a,notificationTopicArn:u,webhookUrl:e.webhookUrl})),r[`${e.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${e.slug}PinpointApp`}},r[`${e.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${e.slug}SmsSendLambda`,"Arn"]}},r[`${e.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${e.slug}SmsNotificationTopic`}},r[`${e.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${e.slug}SmsMessageLogTable`}},{resources:n,outputs:r}}}function ht(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((i)=>i.charAt(0).toUpperCase()+i.slice(1)).join("")||"User"}function xr(e,n){let r=(e||n).replace(/^\/+|\/+$/g,"");if(!r||r.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${n}`);return r}function kr(e){let n=e.storage;if(n?.type==="efs"){let i="fileSystemId"in n?n.fileSystemId:void 0;if(!i||typeof i==="string"&&!i.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:i,posixProfile:n.posixProfile}}let r=(n?.type==="s3"?n.bucket??e.bucket:e.bucket)?.trim();if(!r)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:r}}function Mr(e,n,r){let i=n.posixProfile??r;if(!i)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let s of[i.uid,i.gid,...i.secondaryGids??[]])if(!Number.isInteger(s)||s<0||s>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${s}`);return{Uid:i.uid,Gid:i.gid,...i.secondaryGids?.length?{SecondaryGids:i.secondaryGids}:{}}}function Lr(e,n){return typeof e==="string"?`/${e}/${n}`:{"Fn::Sub":[`/\${FileSystemId}/${n}`,{FileSystemId:e}]}}function Or(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 rs{static create(e){let n=kr(e),r=n.type==="efs"?"EFS":"S3",i=e.endpointType??"PUBLIC";if(i==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let s=`${ht(e.slug)}${ht(e.environment)}Sftp`,a=`${s}Server`,c={},u;if(e.logging!==!1){let d=`${s}LoggingRole`;c[d]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TransferLogging",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:log-group:/aws/transfer/*"}]}}]}},u={"Fn::GetAtt":[d,"Arn"]}}c[a]={Type:"AWS::Transfer::Server",Properties:{Domain:r,EndpointType:i,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...i==="VPC"?{EndpointDetails:{VpcId:e.endpointDetails.vpcId,SubnetIds:e.endpointDetails.subnetIds,...e.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:e.endpointDetails.securityGroupIds}:{},...e.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:e.endpointDetails.addressAllocationIds}:{}}}:{},...e.securityPolicyName?{SecurityPolicyName:e.securityPolicyName}:{},...u?{LoggingRole:u}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[d,m]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(d))throw Error(`sftp: invalid username ${d}`);if(!m.sshPublicKeys.length)throw Error(`sftp: user ${d} requires at least one SSH public key`);let p=ht(d),g=xr(m.homeDirectory,d),y=`${s}${p}User`,f=m.roleArn;if(!f){let h=`${s}${p}Role`,S;if(n.type==="efs")S=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Or(n.fileSystemId)}];else{let A=`arn:aws:s3:::${n.bucket}`;S=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:A,Condition:{StringLike:{"s3:prefix":[g,`${g}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${A}/${g}/*`}]}c[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:S}}]}},f={"Fn::GetAtt":[h,"Arn"]}}c[y]={Type:"AWS::Transfer::User",DependsOn:[a],Properties:{ServerId:{Ref:a},UserName:d,Role:f,HomeDirectoryType:"PATH",HomeDirectory:n.type==="efs"?Lr(n.fileSystemId,g):`/${n.bucket}/${g}`,...n.type==="efs"?{PosixProfile:Mr(d,m,n.posixProfile)}:{},SshPublicKeys:m.sshPublicKeys}}}return{resources:c,serverLogicalId:a,domain:r}}}class qe{static createBedrockRole(e,n){let{slug:r,environment:i,name:s,models:a=["*"],allowStreaming:c=!0}=n,u=s||l({slug:r,environment:i,resourceType:"bedrock-role"}),d=o(u),m=["bedrock:InvokeModel"];if(c)m.push("bedrock:InvokeModelWithResponseStream");let p=a.map((y)=>y==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${y}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:e},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${u}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:m,Resource:p}]}}],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i}]}},logicalId:d}}static createBedrockPolicy(e){let{slug:n,environment:r,name:i,models:s=["*"],allowInvoke:a=!0,allowStreaming:c=!0,allowAsync:u=!1}=e,d=i||l({slug:n,environment:r,resourceType:"bedrock-policy"}),m=o(d),p=[];if(a)p.push("bedrock:InvokeModel");if(c)p.push("bedrock:InvokeModelWithResponseStream");if(u)p.push("bedrock:InvokeModelAsync");let g=s.map((f)=>f==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${f}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:d,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:p,Resource:g}]}}},logicalId:m}}static enableBedrockForLambda(e){return qe.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return qe.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return qe.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,n=["*"],r=!0){let i=["bedrock:InvokeModel"];if(r)i.push("bedrock:InvokeModelWithResponseStream");let s=n.map((a)=>a==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${a}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:i,Resource:s}]}}),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 Yt{static createPostgres(e){return Yt.createRDSInstance("postgres","16.2",e)}static createMysql(e){return Yt.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,n,r){let{slug:i,environment:s,instanceClass:a="db.t3.micro",allocatedStorage:c=20,storageType:u="gp3",masterUsername:d="admin",masterPassword:m,databaseName:p,subnetIds:g,securityGroupIds:y,encrypted:f=!0,kmsKeyId:h,multiAz:S=!1,backupRetentionDays:A=7,publiclyAccessible:R=!1,enableCloudwatchLogs:P=!0,deletionProtection:C=!0}=r,E=l({slug:i,environment:s,resourceType:`${e}-db`}),D=o(E),x,L;if(g&&g.length>0){let O=l({slug:i,environment:s,resourceType:"db-subnet-group"});L=o(O),x={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:O,DBSubnetGroupDescription:`Subnet group for ${E}`,SubnetIds:g,Tags:[{Key:"Name",Value:O},{Key:"Environment",Value:s}]}}}let B={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:E,DBInstanceClass:a,Engine:e,EngineVersion:n,MasterUsername:d,MasterUserPassword:m,AllocatedStorage:c,StorageType:u,StorageEncrypted:f,MultiAZ:S,BackupRetentionPeriod:A,PubliclyAccessible:R,DeletionProtection:C,Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:s}]}};if(p)B.Properties.DBName=p;if(h)B.Properties.KmsKeyId=h;if(L)B.Properties.DBSubnetGroupName=v.Ref(L);if(y&&y.length>0)B.Properties.VPCSecurityGroups=y;if(P)B.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:B,subnetGroup:x,logicalId:D,subnetGroupId:L}}static createReadReplica(e,n){let{slug:r,environment:i,instanceClass:s="db.t3.micro",securityGroupIds:a,publiclyAccessible:c=!1}=n,u=l({slug:r,environment:i,resourceType:"db-replica"}),d=o(u),m={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:u,DBInstanceClass:s,SourceDBInstanceIdentifier:v.Ref(e),PubliclyAccessible:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i},{Key:"Type",Value:"ReadReplica"}]}};if(a&&a.length>0)m.Properties.VPCSecurityGroups=a;return{replica:m,logicalId:d}}static createParameterGroup(e,n,r){let{slug:i,environment:s,parameters:a={}}=r,c=l({slug:i,environment:s,resourceType:"db-params"}),u=o(c),d=e==="postgres"?`postgres${n.split(".")[0]}`:`mysql${n.split(".")[0]}.${n.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:c,Description:`Parameter group for ${c}`,Family:d,Parameters:a,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:s}]}},logicalId:u}}static enableBackup(e,n=7){return e.Properties.BackupRetentionPeriod=n,e}static createTable(e){let{slug:n,environment:r,tableName:i,partitionKey:s,sortKey:a,billingMode:c="PAY_PER_REQUEST",readCapacity:u=5,writeCapacity:d=5,streamEnabled:m=!1,streamViewType:p="NEW_AND_OLD_IMAGES",encrypted:g=!0,kmsKeyId:y,pointInTimeRecovery:f=!0,ttlAttribute:h}=e,S=i||l({slug:n,environment:r,resourceType:"table"}),A=o(S),R=[{AttributeName:s.name,AttributeType:s.type}];if(a)R.push({AttributeName:a.name,AttributeType:a.type});let P=[{AttributeName:s.name,KeyType:"HASH"}];if(a)P.push({AttributeName:a.name,KeyType:"RANGE"});let C={Type:"AWS::DynamoDB::Table",Properties:{TableName:S,BillingMode:c,AttributeDefinitions:R,KeySchema:P,Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:r}]}};if(c==="PROVISIONED")C.Properties.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(m)C.Properties.StreamSpecification={StreamViewType:p};if(g)C.Properties.SSESpecification={SSEEnabled:!0,SSEType:y?"KMS":"AES256",KMSMasterKeyId:y};if(f)C.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(h)C.Properties.TimeToLiveSpecification={AttributeName:h,Enabled:!0};return{table:C,logicalId:A}}static addGlobalSecondaryIndex(e,n){let{indexName:r,partitionKey:i,sortKey:s,projectionType:a="ALL",nonKeyAttributes:c,readCapacity:u=5,writeCapacity:d=5}=n;if(!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===i.name))e.Properties.AttributeDefinitions.push({AttributeName:i.name,AttributeType:i.type});if(s&&!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===s.name))e.Properties.AttributeDefinitions.push({AttributeName:s.name,AttributeType:s.type});let m=[{AttributeName:i.name,KeyType:"HASH"}];if(s)m.push({AttributeName:s.name,KeyType:"RANGE"});let p={IndexName:r,KeySchema:m,Projection:{ProjectionType:a,NonKeyAttributes:a==="INCLUDE"?c:void 0},ProvisionedThroughput:void 0};if(e.Properties.BillingMode==="PROVISIONED")p.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(!e.Properties.GlobalSecondaryIndexes)e.Properties.GlobalSecondaryIndexes=[];return e.Properties.GlobalSecondaryIndexes.push(p),e}static enableStreams(e,n="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:n},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:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:s="7.1",port:a=6379,subnetIds:c,securityGroupIds:u,numCacheClusters:d=2,automaticFailover:m=!0,multiAz:p=!0,clusterMode:g=!1,numNodeGroups:y=1,replicasPerNodeGroup:f=1,atRestEncryption:h=!0,transitEncryption:S=!0,authToken:A,kmsKeyId:R,snapshotRetentionDays:P=7,snapshotWindow:C,maintenanceWindow:E}=e,D=l({slug:n,environment:r,resourceType:"redis"}),x=o(D),L,B;if(c&&c.length>0){let F=l({slug:n,environment:r,resourceType:"cache-subnet-group"});B=o(F),L={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:F,Description:`Subnet group for ${D}`,SubnetIds:c,Tags:[{Key:"Name",Value:F},{Key:"Environment",Value:r}]}}}let O={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:D,ReplicationGroupDescription:`Redis cluster for ${n} ${r}`,Engine:"redis",EngineVersion:s,CacheNodeType:i,Port:a,AutomaticFailoverEnabled:m,MultiAZEnabled:p,AtRestEncryptionEnabled:h,TransitEncryptionEnabled:S,SnapshotRetentionLimit:P,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:r}]}};if(g)O.Properties.NumNodeGroups=y,O.Properties.ReplicasPerNodeGroup=f;else O.Properties.NumCacheClusters=d;if(A)O.Properties.AuthToken=A;if(R)O.Properties.KmsKeyId=R;if(B)O.Properties.CacheSubnetGroupName=v.Ref(B);if(u&&u.length>0)O.Properties.SecurityGroupIds=u;if(C)O.Properties.SnapshotWindow=C;if(E)O.Properties.PreferredMaintenanceWindow=E;return{replicationGroup:O,subnetGroup:L,logicalId:x,subnetGroupId:B}}static createMemcached(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:s="1.6.22",port:a=11211,numCacheNodes:c=2,subnetIds:u,securityGroupIds:d,azMode:m="cross-az",preferredAzs:p,maintenanceWindow:g}=e,y=l({slug:n,environment:r,resourceType:"memcached"}),f=o(y),h,S;if(u&&u.length>0){let R=l({slug:n,environment:r,resourceType:"cache-subnet-group"});S=o(R),h={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:R,Description:`Subnet group for ${y}`,SubnetIds:u,Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:r}]}}}let A={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:y,CacheNodeType:i,Engine:"memcached",EngineVersion:s,NumCacheNodes:c,Port:a,AZMode:m,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(S)A.Properties.CacheSubnetGroupName=v.Ref(S);if(d&&d.length>0)A.Properties.VpcSecurityGroupIds=d;if(p&&p.length>0)A.Properties.PreferredAvailabilityZones=p;if(g)A.Properties.PreferredMaintenanceWindow=g;return{cluster:A,subnetGroup:h,logicalId:f,subnetGroupId:S}}static enableClusterMode(e,n=3,r=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=n,e.Properties.ReplicasPerNodeGroup=r,e}static createRedisParameterGroup(e,n){let{slug:r,environment:i,parameters:s={}}=n,a=l({slug:r,environment:i,resourceType:"redis-params"}),c=o(a);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${a}`,Properties:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i}]}},logicalId:c}}static createMemcachedParameterGroup(e,n){let{slug:r,environment:i,parameters:s={}}=n,a=l({slug:r,environment:i,resourceType:"memcached-params"}),c=o(a);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${a}`,Properties:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i}]}},logicalId:c}}static NodeTypes={T3_Micro:"cache.t3.micro",T3_Small:"cache.t3.small",T3_Medium:"cache.t3.medium",T4g_Micro:"cache.t4g.micro",T4g_Small:"cache.t4g.small",T4g_Medium:"cache.t4g.medium",M5_Large:"cache.m5.large",M5_XLarge:"cache.m5.xlarge",M5_2XLarge:"cache.m5.2xlarge",R5_Large:"cache.r5.large",R5_XLarge:"cache.r5.xlarge",R5_2XLarge:"cache.r5.2xlarge",R5_4XLarge:"cache.r5.4xlarge",R6g_Large:"cache.r6g.large",R6g_XLarge:"cache.r6g.xlarge",R6g_2XLarge:"cache.r6g.2xlarge"}}class Ie{static createUser(e){let{slug:n,environment:r,userName:i,groups:s,managedPolicyArns:a}=e,c=i||l({slug:n,environment:r,resourceType:"user"}),u=o(c),d={Type:"AWS::IAM::User",Properties:{UserName:c,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}};if(s&&s.length>0)d.Properties.Groups=s;if(a&&a.length>0)d.Properties.ManagedPolicyArns=a;return{user:d,logicalId:u}}static createRole(e){let{slug:n,environment:r,roleName:i,servicePrincipal:s,awsPrincipal:a,managedPolicyArns:c}=e,u=i||l({slug:n,environment:r,resourceType:"role"}),d=o(u),m={};if(s)m.Service=s;if(a)m.AWS=a;let p={Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.ManagedPolicyArns=c;return{role:p,logicalId:d}}static createGroup(e){let{slug:n,environment:r,groupName:i,managedPolicyArns:s}=e,a=i||l({slug:n,environment:r,resourceType:"group"}),c=o(a),u={Type:"AWS::IAM::Group",Properties:{GroupName:a}};if(s&&s.length>0)u.Properties.ManagedPolicyArns=s;return{group:u,logicalId:c}}static createPolicy(e){let{slug:n,environment:r,policyName:i,description:s,statements:a}=e,c=i||l({slug:n,environment:r,resourceType:"policy"}),u=o(c),d=a.map((p)=>({Sid:p.sid,Effect:p.effect||"Allow",Action:p.actions,Resource:p.resources,Condition:p.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,Description:s||`Managed policy for ${c}`,PolicyDocument:{Version:"2012-10-17",Statement:d}}},logicalId:u}}static attachPolicyToRole(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static attachPolicyToUser(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static attachPolicyToGroup(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static addInlinePolicyToRole(e,n,r){if(!e.Properties.Policies)e.Properties.Policies=[];let i=r.map((s)=>({Effect:s.effect||"Allow",Action:s.actions,Resource:s.resources}));return e.Properties.Policies.push({PolicyName:n,PolicyDocument:{Version:"2012-10-17",Statement:i}}),e}static addInlinePolicyToUser(e,n,r){if(!e.Properties.Policies)e.Properties.Policies=[];let i=r.map((s)=>({Effect:s.effect||"Allow",Action:s.actions,Resource:s.resources}));return e.Properties.Policies.push({PolicyName:n,PolicyDocument:{Version:"2012-10-17",Statement:i}}),e}static createAccessKey(e,n){let{slug:r,environment:i,status:s="Active"}=n,a=l({slug:r,environment:i,resourceType:"access-key"}),c=o(a);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:v.Ref(e),Status:s}},logicalId:c}}static createInstanceProfile(e,n){let{slug:r,environment:i,profileName:s}=n,a=s||l({slug:r,environment:i,resourceType:"instance-profile"}),c=o(a);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:a,Roles:[v.Ref(e)]}},logicalId:c}}static ManagedPolicies={AdministratorAccess:"arn:aws:iam::aws:policy/AdministratorAccess",PowerUserAccess:"arn:aws:iam::aws:policy/PowerUserAccess",ReadOnlyAccess:"arn:aws:iam::aws:policy/ReadOnlyAccess",S3FullAccess:"arn:aws:iam::aws:policy/AmazonS3FullAccess",S3ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",DynamoDBFullAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",DynamoDBReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess",RDSFullAccess:"arn:aws:iam::aws:policy/AmazonRDSFullAccess",RDSReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess",LambdaFullAccess:"arn:aws:iam::aws:policy/AWSLambda_FullAccess",LambdaReadOnlyAccess:"arn:aws:iam::aws:policy/AWSLambda_ReadOnlyAccess",LambdaBasicExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",LambdaVPCAccessExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole",EC2FullAccess:"arn:aws:iam::aws:policy/AmazonEC2FullAccess",EC2ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess",EC2ContainerRegistryReadOnly:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",EC2ContainerRegistryPowerUser:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser",ECSTaskExecutionRole:"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",ECSFullAccess:"arn:aws:iam::aws:policy/AmazonECS_FullAccess",CloudWatchFullAccess:"arn:aws:iam::aws:policy/CloudWatchFullAccess",CloudWatchLogsFullAccess:"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess",SESFullAccess:"arn:aws:iam::aws:policy/AmazonSESFullAccess",SNSFullAccess:"arn:aws:iam::aws:policy/AmazonSNSFullAccess",SQSFullAccess:"arn:aws:iam::aws:policy/AmazonSQSFullAccess",SecretsManagerReadWrite:"arn:aws:iam::aws:policy/SecretsManagerReadWrite"};static ServicePrincipals={Lambda:"lambda.amazonaws.com",EC2:"ec2.amazonaws.com",ECS:"ecs.amazonaws.com",ECSTaskExecution:"ecs-tasks.amazonaws.com",APIGateway:"apigateway.amazonaws.com",Events:"events.amazonaws.com",States:"states.amazonaws.com",CodeBuild:"codebuild.amazonaws.com",CodeDeploy:"codedeploy.amazonaws.com",CloudFormation:"cloudformation.amazonaws.com"};static createCiCdUser(e){let{slug:n,environment:r,permissions:i,createAccessKey:s=!0}=e,a={},c=[];if(i.s3Buckets&&i.s3Buckets.length>0)c.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...i.s3Buckets,...i.s3Buckets.map((f)=>`${f}/*`)]});if(i.cloudFrontDistributions&&i.cloudFrontDistributions.length>0)c.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:i.cloudFrontDistributions});if(i.ecrRepositories&&i.ecrRepositories.length>0)c.push({sid:"ECRAccess",actions:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:GetRepositoryPolicy","ecr:DescribeRepositories","ecr:ListImages","ecr:DescribeImages","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:i.ecrRepositories}),c.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(i.ecsServices&&i.ecsServices.length>0)c.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:i.ecsServices}),c.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),c.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(i.cloudFormationStacks&&i.cloudFormationStacks.length>0)c.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:i.cloudFormationStacks});if(i.lambdaFunctions&&i.lambdaFunctions.length>0)c.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:i.lambdaFunctions});if(i.secretsManagerSecrets&&i.secretsManagerSecrets.length>0)c.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:i.secretsManagerSecrets});let{policy:u,logicalId:d}=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${n} (${r})`,statements:c});a[d]=u;let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cicd-user"}),managedPolicyArns:[v.Ref(d)]});a[p]=m;let g,y;if(s){let f=Ie.createAccessKey(p,{slug:n,environment:r});g=f.accessKey,y=f.logicalId,a[y]=g}return{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:a}}static createCrossAccountRole(e){let{slug:n,environment:r,trustedAccountIds:i,externalId:s,permissions:a,maxSessionDuration:c=3600}=e,u={},{policy:d,logicalId:m}=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${n} (${r})`,statements:a});u[m]=d;let p=l({slug:n,environment:r,resourceType:"cross-account-role"}),g=o(p),y={};if(s)y.StringEquals={"sts:ExternalId":s};let f={Type:"AWS::IAM::Role",Properties:{RoleName:p,MaxSessionDuration:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:i.map((h)=>`arn:aws:iam::${h}:root`)},Action:"sts:AssumeRole",...Object.keys(y).length>0?{Condition:y}:{}}]},ManagedPolicyArns:[v.Ref(m)],Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Cross-Account Access"}]}};return u[g]=f,{role:f,policy:d,roleLogicalId:g,policyLogicalId:m,resources:u}}static createCliUser(e){let{slug:n,environment:r,permissions:i="readonly"}=e,s={},a=[],c=[];switch(i){case"readonly":c=[Ie.ManagedPolicies.ReadOnlyAccess];break;case"deploy":a=[{sid:"S3Deploy",actions:["s3:*"],resources:"*"},{sid:"CloudFrontDeploy",actions:["cloudfront:*"],resources:"*"},{sid:"ECSDeploy",actions:["ecs:*"],resources:"*"},{sid:"ECRDeploy",actions:["ecr:*"],resources:"*"},{sid:"LambdaDeploy",actions:["lambda:*"],resources:"*"},{sid:"CloudFormationDeploy",actions:["cloudformation:*"],resources:"*"},{sid:"IAMPassRole",actions:["iam:PassRole"],resources:"*"}];break;case"admin":c=[Ie.ManagedPolicies.AdministratorAccess];break}let u,d;if(a.length>0){let f=Ie.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cli-policy"}),description:`CLI access policy for ${n} (${r})`,statements:a});u=f.policy,d=f.logicalId,s[d]=u,c=[v.Ref(d)]}let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cli-user"}),managedPolicyArns:c});s[p]=m;let{accessKey:g,logicalId:y}=Ie.createAccessKey(p,{slug:n,environment:r});return s[y]=g,{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:s}}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((n)=>`${n}/*`)}],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 ns{static createRestApi(e){let{slug:n,environment:r,name:i,description:s,endpointType:a="REGIONAL",binaryMediaTypes:c,compressionSize:u}=e,d=i||l({slug:n,environment:r,resourceType:"rest-api"}),m=o(d),p={Type:"AWS::ApiGateway::RestApi",Properties:{Name:d,Description:s||`REST API for ${n} ${r}`,EndpointConfiguration:{Types:[a]},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.BinaryMediaTypes=c;if(u!==void 0)p.Properties.MinimumCompressionSize=u;return{restApi:p,logicalId:m}}static createHttpApi(e){let{slug:n,environment:r,name:i,description:s,corsEnabled:a=!0,corsOrigins:c=["*"],corsMethods:u=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:d=["*"],corsMaxAge:m=86400,corsAllowCredentials:p=!1}=e,g=i||l({slug:n,environment:r,resourceType:"http-api"}),y=o(g),f={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:g,Description:s||`HTTP API for ${n} ${r}`,ProtocolType:"HTTP",Tags:{Name:g,Environment:r}}};if(a)f.Properties.CorsConfiguration={AllowOrigins:c,AllowMethods:u,AllowHeaders:d,MaxAge:m,AllowCredentials:p};return{httpApi:f,logicalId:y}}static createWebSocketApi(e){let{slug:n,environment:r,name:i,description:s}=e,a=i||l({slug:n,environment:r,resourceType:"ws-api"}),c=o(a);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:a,Description:s||`WebSocket API for ${n} ${r}`,ProtocolType:"WEBSOCKET",Tags:{Name:a,Environment:r}}},logicalId:c}}static createDeployment(e,n){let{slug:r,environment:i,description:s}=n,a=l({slug:r,environment:i,resourceType:"api-deployment"}),c=o(a);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:v.Ref(e),Description:s||`Deployment for ${a}`}},logicalId:c}}static createStage(e,n,r){let{slug:i,environment:s,stageName:a,description:c,cacheEnabled:u=!1,cacheSize:d="0.5",variables:m,throttling:p}=r,g=l({slug:i,environment:s,resourceType:"api-stage"}),y=o(g),f={Type:"AWS::ApiGateway::Stage",Properties:{StageName:a||s,RestApiId:v.Ref(e),DeploymentId:v.Ref(n),Description:c,CacheClusterEnabled:u,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:s}]}};if(u)f.Properties.CacheClusterSize=d;if(m)f.Properties.Variables=m;if(p)f.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:p.burstLimit,ThrottlingRateLimit:p.rateLimit}];return{stage:f,logicalId:y}}static createAuthorizer(e,n){let{slug:r,environment:i,name:s,type:a,functionArn:c,identitySource:u,userPoolArns:d,ttl:m=300}=n,p=s||l({slug:r,environment:i,resourceType:"api-authorizer"}),g=o(p),y={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:p,Type:a,RestApiId:v.Ref(e),AuthorizerResultTtlInSeconds:m}};if(a==="TOKEN"||a==="REQUEST"){if(!c)throw Error("Lambda authorizer requires functionArn");y.Properties.AuthorizerUri=c,y.Properties.IdentitySource=u||"method.request.header.Authorization"}if(a==="COGNITO_USER_POOLS"){if(!d||d.length===0)throw Error("Cognito authorizer requires userPoolArns");y.Properties.ProviderARNs=d,y.Properties.IdentitySource=u||"method.request.header.Authorization"}return{authorizer:y,logicalId:g}}static setCors(e,n={}){let{origins:r=["*"],methods:i=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:s=["*"],maxAge:a=86400,allowCredentials:c=!1}=n;return e.Properties.CorsConfiguration={AllowOrigins:r,AllowMethods:i,AllowHeaders:s,MaxAge:a,AllowCredentials:c},e}static addThrottling(e,n=5000,r=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:n,ThrottlingRateLimit:r}),e}static enableCaching(e,n="0.5",r=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=n,!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:r}),e}static CacheSizes={Small:"0.5",Medium:"1.6",Large:"6.1",XLarge:"13.5",XXLarge:"28.4",XXXLarge:"58.2",Huge:"118",Massive:"237"};static ThrottlingPresets={Light:{burstLimit:100,rateLimit:50},Medium:{burstLimit:500,rateLimit:250},Heavy:{burstLimit:2000,rateLimit:1000},Default:{burstLimit:5000,rateLimit:1e4}}}class Le{static createTopic(e){let{slug:n,environment:r,topicName:i,displayName:s,encrypted:a=!1,kmsKeyId:c}=e,u=i||l({slug:n,environment:r,resourceType:"topic"}),d=o(u),m={Type:"AWS::SNS::Topic",Properties:{TopicName:u,DisplayName:s||u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(a&&c)m.Properties.KmsMasterKeyId=c;return{topic:m,logicalId:d}}static subscribe(e,n){let{slug:r,environment:i,protocol:s,endpoint:a,filterPolicy:c,rawMessageDelivery:u=!1}=n,d=l({slug:r,environment:i,resourceType:"subscription"}),m=a.replace(/[^a-zA-Z0-9]/g,""),p=m.length>12?m.slice(-12):m,g=o(`${d}-${s}-${p}`),y={Type:"AWS::SNS::Subscription",Properties:{TopicArn:v.Ref(e),Protocol:s,Endpoint:a,RawMessageDelivery:u}};if(c)y.Properties.FilterPolicy=c;return{subscription:y,logicalId:g}}static subscribeEmail(e,n,r){return Le.subscribe(e,{...r,protocol:"email",endpoint:n})}static subscribeLambda(e,n,r){return Le.subscribe(e,{...r,protocol:"lambda",endpoint:n,rawMessageDelivery:!0})}static subscribeSqs(e,n,r){return Le.subscribe(e,{...r,protocol:"sqs",endpoint:n})}static subscribeHttp(e,n,r){let i=n.startsWith("https://")?"https":"http";return Le.subscribe(e,{...r,protocol:i,endpoint:n})}static subscribeSms(e,n,r){return Le.subscribe(e,{...r,protocol:"sms",endpoint:n})}static setTopicPolicy(e,n){let{slug:r,environment:i,allowedPrincipals:s,allowedServices:a,actions:c="SNS:Publish"}=n,u=l({slug:r,environment:i,resourceType:"topic-policy"}),d=o(u),m={};if(s)m.AWS=s;if(a)m.Service=a;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[v.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:c,Resource:v.Ref(e)}]}}},logicalId:d}}static allowCloudWatchAlarms(e,n){return Le.setTopicPolicy(e,{...n,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,n){return Le.setTopicPolicy(e,{...n,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,n){return Le.setTopicPolicy(e,{...n,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,n){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=n,e}static addInlineSubscription(e,n,r){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:n,Endpoint:r}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,n,r)=>({[e]:[{numeric:[">=",n,"<=",r]}]}),prefix:(e,n)=>({[e]:[{prefix:n}]}),and:(...e)=>Object.assign({},...e),exists:(e,n)=>({[e]:[{exists:n}]})};static UseCases={createAlertTopic:(e)=>Le.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>Le.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>Le.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class fu{static createStateMachine(e){let{slug:n,environment:r,stateMachineName:i,type:s="STANDARD",definition:a,roleArn:c,loggingConfiguration:u,tracingConfiguration:d}=e,m=i||l({slug:n,environment:r,resourceType:"state-machine"}),p=o(m),g,y,f;if(c)f=c;else{let S=l({slug:n,environment:r,resourceType:"state-machine-role"});y=o(S),g={Type:"AWS::IAM::Role",Properties:{RoleName:S,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:S},{Key:"Environment",Value:r}]}},f=v.GetAtt(y,"Arn")}let h={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:m,StateMachineType:s,DefinitionString:JSON.stringify(a),RoleArn:f,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(u)h.Properties.LoggingConfiguration={Level:u.level,IncludeExecutionData:u.includeExecutionData,Destinations:u.destinations?.map((S)=>({CloudWatchLogsLogGroup:{LogGroupArn:S}}))};if(d)h.Properties.TracingConfiguration={Enabled:d.enabled};return{stateMachine:h,logicalId:p,role:g,roleLogicalId:y}}static createLambdaTask(e,n){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:n?.parameters||{"Input.$":"$"}},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createDynamoDBTask(e,n,r,i){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:n,...r},ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createSNSPublishTask(e,n,r){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSQSSendMessageTask(e,n,r){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createPassState(e){return{Type:"Pass",Result:e?.result,ResultPath:e?.resultPath,Parameters:e?.parameters,Next:e?.next,End:e?.end}}static createWaitState(e){return{Type:"Wait",Seconds:e.seconds,Timestamp:e.timestamp,SecondsPath:e.secondsPath,TimestampPath:e.timestampPath,Next:e.next,End:e.end}}static createChoiceState(e,n){return{Type:"Choice",Choices:e,Default:n}}static createParallelState(e,n){return{Type:"Parallel",Branches:e,ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createMapState(e,n){return{Type:"Map",ItemsPath:n?.itemsPath||"$.items",Iterator:e,MaxConcurrency:n?.maxConcurrency,ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,n){return{Type:"Fail",Error:e,Cause:n}}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,n,r,i)=>({ErrorEquals:e,IntervalSeconds:n,MaxAttempts:r,BackoffRate:i})};static CatchPolicies={all:(e,n)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:n||"$.error"}),specific:(e,n,r)=>({ErrorEquals:e,Next:n,ResultPath:r||"$.error"})};static Patterns={sequential:(e,n,r)=>{let i={};return r.forEach((s,a)=>{let c=a===r.length-1;i[s.name]={...s.state,Next:c?void 0:r[a+1].name,End:c}}),{Comment:"Sequential workflow",StartAt:r[0].name,States:i}},fanout:(e,n,r)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:r.map((i)=>i.definition),End:!0}}}),map:(e,n,r,i)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:r,MaxConcurrency:i,End:!0}}}),withErrorHandling:(e,n,r,i)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...r,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:i,Success:{Type:"Succeed"}}})}}class zi{static createAlarm(e){let{slug:n,environment:r,alarmName:i,metricName:s,namespace:a,statistic:c="Average",period:u=300,evaluationPeriods:d=1,threshold:m,comparisonOperator:p,treatMissingData:g="notBreaching",actionsEnabled:y=!0,alarmActions:f,okActions:h,insufficientDataActions:S,dimensions:A,unit:R,datapointsToAlarm:P}=e,C=i||l({slug:n,environment:r,resourceType:"alarm"}),E=o(C),D={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:C,MetricName:s,Namespace:a,Statistic:c,Period:u,EvaluationPeriods:d,Threshold:m,ComparisonOperator:p,TreatMissingData:g,ActionsEnabled:y}};if(f&&f.length>0)D.Properties.AlarmActions=f;if(h&&h.length>0)D.Properties.OKActions=h;if(S&&S.length>0)D.Properties.InsufficientDataActions=S;if(A)D.Properties.Dimensions=Object.entries(A).map(([x,L])=>({Name:x,Value:L}));if(R)D.Properties.Unit=R;if(P!==void 0)D.Properties.DatapointsToAlarm=P;return{alarm:D,logicalId:E}}static createCompositeAlarm(e){let{slug:n,environment:r,alarmName:i,alarmRule:s,actionsEnabled:a=!0,alarmActions:c,okActions:u,insufficientDataActions:d}=e,m=i||l({slug:n,environment:r,resourceType:"composite-alarm"}),p=o(m),g={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:m,AlarmRule:s,ActionsEnabled:a}};if(c&&c.length>0)g.Properties.AlarmActions=c;if(u&&u.length>0)g.Properties.OKActions=u;if(d&&d.length>0)g.Properties.InsufficientDataActions=d;return{alarm:g,logicalId:p}}static createDashboard(e){let{slug:n,environment:r,dashboardName:i,widgets:s}=e,a=i||l({slug:n,environment:r,resourceType:"dashboard"}),c=o(a),u={widgets:s.map((m)=>({type:m.type,x:m.x,y:m.y,width:m.width,height:m.height,properties:m.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:a,DashboardBody:JSON.stringify(u)}},logicalId:c}}static createLogGroup(e){let{slug:n,environment:r,logGroupName:i,retentionInDays:s,kmsKeyId:a}=e,c=i||l({slug:n,environment:r,resourceType:"log-group"}),u=o(c),d={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:c}};if(s!==void 0)d.Properties.RetentionInDays=s;if(a)d.Properties.KmsKeyId=a;return{logGroup:d,logicalId:u}}static createLogStream(e,n){let{slug:r,environment:i,logStreamName:s}=n,a=s||l({slug:r,environment:i,resourceType:"log-stream"}),c=o(a);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:v.Ref(e),LogStreamName:a}},logicalId:c}}static createMetricFilter(e,n){let{slug:r,environment:i,filterName:s,filterPattern:a,metricTransformations:c}=n,u=s||l({slug:r,environment:i,resourceType:"metric-filter"}),d=o(u);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:v.Ref(e),FilterPattern:a,MetricTransformations:c.map((p)=>({MetricName:p.metricName,MetricNamespace:p.metricNamespace,MetricValue:p.metricValue,DefaultValue:p.defaultValue,Unit:p.unit}))}},logicalId:d}}static AlarmTypes={highCpu:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:s?[s]:void 0}),highMemory:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:s?[s]:void 0}),highDisk:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:s?[s]:void 0}),lambdaErrors:(e,n,r,i=5,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:s?[s]:void 0}),lambdaThrottles:(e,n,r,i=10,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:s?[s]:void 0}),apiGateway5xxErrors:(e,n,r,i=10,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:s?[s]:void 0}),apiGateway4xxErrors:(e,n,r,i=50,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:s?[s]:void 0}),dynamoDBThrottles:(e,n,r,i=5,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:r},alarmActions:s?[s]:void 0}),rdsCpu:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:s?[s]:void 0}),rdsFreeStorage:(e,n,r,i=5368709120,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:s?[s]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,n,r,i=100,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:r},alarmActions:s?[s]:void 0}),albUnhealthyTargets:(e,n,r,i,s=1,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:s,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:r,TargetGroup:i},alarmActions:a?[a]:void 0}),sesBounceRate:(e,n,r=5,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),sesComplaintRate:(e,n,r=0.1,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),smsDeliveryFailure:(e,n,r,i=10,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:r},alarmActions:s?[s]:void 0}),smsSpendLimit:(e,n,r=100,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),connectMissedCalls:(e,n,r,i=5,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:s?[s]:void 0})};static DashboardWidgets={metric:(e,n,r,i,s,a)=>({type:"metric",x:e,y:n,width:r,height:i,properties:{metrics:s,title:a||"Metrics",region:"us-east-1",period:300}}),text:(e,n,r,i,s)=>({type:"text",x:e,y:n,width:r,height:i,properties:{markdown:s}}),log:(e,n,r,i,s,a)=>({type:"log",x:e,y:n,width:r,height:i,properties:{query:`SOURCE '${s.join("' | SOURCE '")}'
|
|
2274
|
+
`;class Ie{static LambdaCode={send:St,receive:dn,deliveryStatus:un};static createPinpointApp(e){return{[`${e.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:e.name||`${e.slug}-sms`}}}}static createSmsChannel(e){let n={ApplicationId:e.applicationId,Enabled:e.enabled!==!1};if(e.senderId)n.SenderId=e.senderId;if(e.shortCode)n.ShortCode=e.shortCode;return{[`${e.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:n}}}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:Ie.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:Ie.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:Ie.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 n={},r={};Object.assign(n,Ie.createPinpointApp({slug:e.slug})),Object.assign(n,Ie.createSmsChannel({slug:e.slug,applicationId:{Ref:`${e.slug}PinpointApp`},senderId:e.senderId})),Object.assign(n,Ie.createSmsLambdaRole({slug:e.slug})),Object.assign(n,Ie.createMessageLogTable({slug:e.slug})),Object.assign(n,Ie.createOptOutTable({slug:e.slug})),Object.assign(n,Ie.createNotificationTopic({slug:e.slug}));let i={"Fn::GetAtt":[`${e.slug}SmsLambdaRole`,"Arn"]},s={Ref:`${e.slug}PinpointApp`},a={Ref:`${e.slug}SmsMessageLogTable`},c={Ref:`${e.slug}SmsOptOutTable`},u={Ref:`${e.slug}SmsNotificationTopic`};if(Object.assign(n,Ie.createSendLambda({slug:e.slug,roleArn:i,pinpointAppId:s,messageLogTable:a,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(n,Ie.createReceiveLambda({slug:e.slug,roleArn:i,optOutTable:c,messageLogTable:a,notificationTopicArn:u,webhookUrl:e.webhookUrl}));return Object.assign(n,Ie.createDeliveryStatusLambda({slug:e.slug,roleArn:i,messageLogTable:a,notificationTopicArn:u,webhookUrl:e.webhookUrl})),r[`${e.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${e.slug}PinpointApp`}},r[`${e.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${e.slug}SmsSendLambda`,"Arn"]}},r[`${e.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${e.slug}SmsNotificationTopic`}},r[`${e.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${e.slug}SmsMessageLogTable`}},{resources:n,outputs:r}}}function At(e){return e.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((i)=>i.charAt(0).toUpperCase()+i.slice(1)).join("")||"User"}function ti(e,n){let r=(e||n).replace(/^\/+|\/+$/g,"");if(!r||r.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${n}`);return r}function ni(e){let n=e.storage;if(n?.type==="efs"){let i="fileSystemId"in n?n.fileSystemId:void 0;if(!i||typeof i==="string"&&!i.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:i,posixProfile:n.posixProfile}}let r=(n?.type==="s3"?n.bucket??e.bucket:e.bucket)?.trim();if(!r)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:r}}function ri(e,n,r){let i=n.posixProfile??r;if(!i)throw Error(`sftp: user ${e} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let s of[i.uid,i.gid,...i.secondaryGids??[]])if(!Number.isInteger(s)||s<0||s>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${s}`);return{Uid:i.uid,Gid:i.gid,...i.secondaryGids?.length?{SecondaryGids:i.secondaryGids}:{}}}function ii(e,n){return typeof e==="string"?`/${e}/${n}`:{"Fn::Sub":[`/\${FileSystemId}/${n}`,{FileSystemId:e}]}}function si(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 as{static create(e){let n=ni(e),r=n.type==="efs"?"EFS":"S3",i=e.endpointType??"PUBLIC";if(i==="VPC"&&(!e.endpointDetails?.vpcId||!e.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let s=`${At(e.slug)}${At(e.environment)}Sftp`,a=`${s}Server`,c={},u;if(e.logging!==!1){let d=`${s}LoggingRole`;c[d]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TransferLogging",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:log-group:/aws/transfer/*"}]}}]}},u={"Fn::GetAtt":[d,"Arn"]}}c[a]={Type:"AWS::Transfer::Server",Properties:{Domain:r,EndpointType:i,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...i==="VPC"?{EndpointDetails:{VpcId:e.endpointDetails.vpcId,SubnetIds:e.endpointDetails.subnetIds,...e.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:e.endpointDetails.securityGroupIds}:{},...e.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:e.endpointDetails.addressAllocationIds}:{}}}:{},...e.securityPolicyName?{SecurityPolicyName:e.securityPolicyName}:{},...u?{LoggingRole:u}:{},Tags:[{Key:"Project",Value:e.slug},{Key:"Environment",Value:e.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[d,m]of Object.entries(e.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(d))throw Error(`sftp: invalid username ${d}`);if(!m.sshPublicKeys.length)throw Error(`sftp: user ${d} requires at least one SSH public key`);let p=At(d),g=ti(m.homeDirectory,d),y=`${s}${p}User`,f=m.roleArn;if(!f){let h=`${s}${p}Role`,S;if(n.type==="efs")S=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:si(n.fileSystemId)}];else{let A=`arn:aws:s3:::${n.bucket}`;S=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:A,Condition:{StringLike:{"s3:prefix":[g,`${g}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${A}/${g}/*`}]}c[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:S}}]}},f={"Fn::GetAtt":[h,"Arn"]}}c[y]={Type:"AWS::Transfer::User",DependsOn:[a],Properties:{ServerId:{Ref:a},UserName:d,Role:f,HomeDirectoryType:"PATH",HomeDirectory:n.type==="efs"?ii(n.fileSystemId,g):`/${n.bucket}/${g}`,...n.type==="efs"?{PosixProfile:ri(d,m,n.posixProfile)}:{},SshPublicKeys:m.sshPublicKeys}}}return{resources:c,serverLogicalId:a,domain:r}}}class We{static createBedrockRole(e,n){let{slug:r,environment:i,name:s,models:a=["*"],allowStreaming:c=!0}=n,u=s||l({slug:r,environment:i,resourceType:"bedrock-role"}),d=o(u),m=["bedrock:InvokeModel"];if(c)m.push("bedrock:InvokeModelWithResponseStream");let p=a.map((y)=>y==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${y}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:e},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${u}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:m,Resource:p}]}}],Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i}]}},logicalId:d}}static createBedrockPolicy(e){let{slug:n,environment:r,name:i,models:s=["*"],allowInvoke:a=!0,allowStreaming:c=!0,allowAsync:u=!1}=e,d=i||l({slug:n,environment:r,resourceType:"bedrock-policy"}),m=o(d),p=[];if(a)p.push("bedrock:InvokeModel");if(c)p.push("bedrock:InvokeModelWithResponseStream");if(u)p.push("bedrock:InvokeModelAsync");let g=s.map((f)=>f==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${f}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:d,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:p,Resource:g}]}}},logicalId:m}}static enableBedrockForLambda(e){return We.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return We.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return We.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,n=["*"],r=!0){let i=["bedrock:InvokeModel"];if(r)i.push("bedrock:InvokeModelWithResponseStream");let s=n.map((a)=>a==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${a}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:i,Resource:s}]}}),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 er{static createPostgres(e){return er.createRDSInstance("postgres","16.2",e)}static createMysql(e){return er.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,n,r){let{slug:i,environment:s,instanceClass:a="db.t3.micro",allocatedStorage:c=20,storageType:u="gp3",masterUsername:d="admin",masterPassword:m,databaseName:p,subnetIds:g,securityGroupIds:y,encrypted:f=!0,kmsKeyId:h,multiAz:S=!1,backupRetentionDays:A=7,publiclyAccessible:R=!1,enableCloudwatchLogs:P=!0,deletionProtection:C=!0}=r,E=l({slug:i,environment:s,resourceType:`${e}-db`}),D=o(E),x,L;if(g&&g.length>0){let O=l({slug:i,environment:s,resourceType:"db-subnet-group"});L=o(O),x={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:O,DBSubnetGroupDescription:`Subnet group for ${E}`,SubnetIds:g,Tags:[{Key:"Name",Value:O},{Key:"Environment",Value:s}]}}}let B={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:E,DBInstanceClass:a,Engine:e,EngineVersion:n,MasterUsername:d,MasterUserPassword:m,AllocatedStorage:c,StorageType:u,StorageEncrypted:f,MultiAZ:S,BackupRetentionPeriod:A,PubliclyAccessible:R,DeletionProtection:C,Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:s}]}};if(p)B.Properties.DBName=p;if(h)B.Properties.KmsKeyId=h;if(L)B.Properties.DBSubnetGroupName=v.Ref(L);if(y&&y.length>0)B.Properties.VPCSecurityGroups=y;if(P)B.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:B,subnetGroup:x,logicalId:D,subnetGroupId:L}}static createReadReplica(e,n){let{slug:r,environment:i,instanceClass:s="db.t3.micro",securityGroupIds:a,publiclyAccessible:c=!1}=n,u=l({slug:r,environment:i,resourceType:"db-replica"}),d=o(u),m={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:u,DBInstanceClass:s,SourceDBInstanceIdentifier:v.Ref(e),PubliclyAccessible:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i},{Key:"Type",Value:"ReadReplica"}]}};if(a&&a.length>0)m.Properties.VPCSecurityGroups=a;return{replica:m,logicalId:d}}static createParameterGroup(e,n,r){let{slug:i,environment:s,parameters:a={}}=r,c=l({slug:i,environment:s,resourceType:"db-params"}),u=o(c),d=e==="postgres"?`postgres${n.split(".")[0]}`:`mysql${n.split(".")[0]}.${n.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:c,Description:`Parameter group for ${c}`,Family:d,Parameters:a,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:s}]}},logicalId:u}}static enableBackup(e,n=7){return e.Properties.BackupRetentionPeriod=n,e}static createTable(e){let{slug:n,environment:r,tableName:i,partitionKey:s,sortKey:a,billingMode:c="PAY_PER_REQUEST",readCapacity:u=5,writeCapacity:d=5,streamEnabled:m=!1,streamViewType:p="NEW_AND_OLD_IMAGES",encrypted:g=!0,kmsKeyId:y,pointInTimeRecovery:f=!0,ttlAttribute:h}=e,S=i||l({slug:n,environment:r,resourceType:"table"}),A=o(S),R=[{AttributeName:s.name,AttributeType:s.type}];if(a)R.push({AttributeName:a.name,AttributeType:a.type});let P=[{AttributeName:s.name,KeyType:"HASH"}];if(a)P.push({AttributeName:a.name,KeyType:"RANGE"});let C={Type:"AWS::DynamoDB::Table",Properties:{TableName:S,BillingMode:c,AttributeDefinitions:R,KeySchema:P,Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:r}]}};if(c==="PROVISIONED")C.Properties.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(m)C.Properties.StreamSpecification={StreamViewType:p};if(g)C.Properties.SSESpecification={SSEEnabled:!0,SSEType:y?"KMS":"AES256",KMSMasterKeyId:y};if(f)C.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(h)C.Properties.TimeToLiveSpecification={AttributeName:h,Enabled:!0};return{table:C,logicalId:A}}static addGlobalSecondaryIndex(e,n){let{indexName:r,partitionKey:i,sortKey:s,projectionType:a="ALL",nonKeyAttributes:c,readCapacity:u=5,writeCapacity:d=5}=n;if(!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===i.name))e.Properties.AttributeDefinitions.push({AttributeName:i.name,AttributeType:i.type});if(s&&!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===s.name))e.Properties.AttributeDefinitions.push({AttributeName:s.name,AttributeType:s.type});let m=[{AttributeName:i.name,KeyType:"HASH"}];if(s)m.push({AttributeName:s.name,KeyType:"RANGE"});let p={IndexName:r,KeySchema:m,Projection:{ProjectionType:a,NonKeyAttributes:a==="INCLUDE"?c:void 0},ProvisionedThroughput:void 0};if(e.Properties.BillingMode==="PROVISIONED")p.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(!e.Properties.GlobalSecondaryIndexes)e.Properties.GlobalSecondaryIndexes=[];return e.Properties.GlobalSecondaryIndexes.push(p),e}static enableStreams(e,n="NEW_AND_OLD_IMAGES"){return e.Properties.StreamSpecification={StreamViewType:n},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 Hi{static createRedis(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:s="7.1",port:a=6379,subnetIds:c,securityGroupIds:u,numCacheClusters:d=2,automaticFailover:m=!0,multiAz:p=!0,clusterMode:g=!1,numNodeGroups:y=1,replicasPerNodeGroup:f=1,atRestEncryption:h=!0,transitEncryption:S=!0,authToken:A,kmsKeyId:R,snapshotRetentionDays:P=7,snapshotWindow:C,maintenanceWindow:E}=e,D=l({slug:n,environment:r,resourceType:"redis"}),x=o(D),L,B;if(c&&c.length>0){let F=l({slug:n,environment:r,resourceType:"cache-subnet-group"});B=o(F),L={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:F,Description:`Subnet group for ${D}`,SubnetIds:c,Tags:[{Key:"Name",Value:F},{Key:"Environment",Value:r}]}}}let O={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:D,ReplicationGroupDescription:`Redis cluster for ${n} ${r}`,Engine:"redis",EngineVersion:s,CacheNodeType:i,Port:a,AutomaticFailoverEnabled:m,MultiAZEnabled:p,AtRestEncryptionEnabled:h,TransitEncryptionEnabled:S,SnapshotRetentionLimit:P,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:r}]}};if(g)O.Properties.NumNodeGroups=y,O.Properties.ReplicasPerNodeGroup=f;else O.Properties.NumCacheClusters=d;if(A)O.Properties.AuthToken=A;if(R)O.Properties.KmsKeyId=R;if(B)O.Properties.CacheSubnetGroupName=v.Ref(B);if(u&&u.length>0)O.Properties.SecurityGroupIds=u;if(C)O.Properties.SnapshotWindow=C;if(E)O.Properties.PreferredMaintenanceWindow=E;return{replicationGroup:O,subnetGroup:L,logicalId:x,subnetGroupId:B}}static createMemcached(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:s="1.6.22",port:a=11211,numCacheNodes:c=2,subnetIds:u,securityGroupIds:d,azMode:m="cross-az",preferredAzs:p,maintenanceWindow:g}=e,y=l({slug:n,environment:r,resourceType:"memcached"}),f=o(y),h,S;if(u&&u.length>0){let R=l({slug:n,environment:r,resourceType:"cache-subnet-group"});S=o(R),h={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:R,Description:`Subnet group for ${y}`,SubnetIds:u,Tags:[{Key:"Name",Value:R},{Key:"Environment",Value:r}]}}}let A={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:y,CacheNodeType:i,Engine:"memcached",EngineVersion:s,NumCacheNodes:c,Port:a,AZMode:m,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(S)A.Properties.CacheSubnetGroupName=v.Ref(S);if(d&&d.length>0)A.Properties.VpcSecurityGroupIds=d;if(p&&p.length>0)A.Properties.PreferredAvailabilityZones=p;if(g)A.Properties.PreferredMaintenanceWindow=g;return{cluster:A,subnetGroup:h,logicalId:f,subnetGroupId:S}}static enableClusterMode(e,n=3,r=2){return delete e.Properties.NumCacheClusters,e.Properties.NumNodeGroups=n,e.Properties.ReplicasPerNodeGroup=r,e}static createRedisParameterGroup(e,n){let{slug:r,environment:i,parameters:s={}}=n,a=l({slug:r,environment:i,resourceType:"redis-params"}),c=o(a);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${a}`,Properties:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i}]}},logicalId:c}}static createMemcachedParameterGroup(e,n){let{slug:r,environment:i,parameters:s={}}=n,a=l({slug:r,environment:i,resourceType:"memcached-params"}),c=o(a);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${a}`,Properties:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:i}]}},logicalId:c}}static NodeTypes={T3_Micro:"cache.t3.micro",T3_Small:"cache.t3.small",T3_Medium:"cache.t3.medium",T4g_Micro:"cache.t4g.micro",T4g_Small:"cache.t4g.small",T4g_Medium:"cache.t4g.medium",M5_Large:"cache.m5.large",M5_XLarge:"cache.m5.xlarge",M5_2XLarge:"cache.m5.2xlarge",R5_Large:"cache.r5.large",R5_XLarge:"cache.r5.xlarge",R5_2XLarge:"cache.r5.2xlarge",R5_4XLarge:"cache.r5.4xlarge",R6g_Large:"cache.r6g.large",R6g_XLarge:"cache.r6g.xlarge",R6g_2XLarge:"cache.r6g.2xlarge"}}class Pe{static createUser(e){let{slug:n,environment:r,userName:i,groups:s,managedPolicyArns:a}=e,c=i||l({slug:n,environment:r,resourceType:"user"}),u=o(c),d={Type:"AWS::IAM::User",Properties:{UserName:c,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r}]}};if(s&&s.length>0)d.Properties.Groups=s;if(a&&a.length>0)d.Properties.ManagedPolicyArns=a;return{user:d,logicalId:u}}static createRole(e){let{slug:n,environment:r,roleName:i,servicePrincipal:s,awsPrincipal:a,managedPolicyArns:c}=e,u=i||l({slug:n,environment:r,resourceType:"role"}),d=o(u),m={};if(s)m.Service=s;if(a)m.AWS=a;let p={Type:"AWS::IAM::Role",Properties:{RoleName:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.ManagedPolicyArns=c;return{role:p,logicalId:d}}static createGroup(e){let{slug:n,environment:r,groupName:i,managedPolicyArns:s}=e,a=i||l({slug:n,environment:r,resourceType:"group"}),c=o(a),u={Type:"AWS::IAM::Group",Properties:{GroupName:a}};if(s&&s.length>0)u.Properties.ManagedPolicyArns=s;return{group:u,logicalId:c}}static createPolicy(e){let{slug:n,environment:r,policyName:i,description:s,statements:a}=e,c=i||l({slug:n,environment:r,resourceType:"policy"}),u=o(c),d=a.map((p)=>({Sid:p.sid,Effect:p.effect||"Allow",Action:p.actions,Resource:p.resources,Condition:p.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:c,Description:s||`Managed policy for ${c}`,PolicyDocument:{Version:"2012-10-17",Statement:d}}},logicalId:u}}static attachPolicyToRole(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static attachPolicyToUser(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static attachPolicyToGroup(e,n){if(!e.Properties.ManagedPolicyArns)e.Properties.ManagedPolicyArns=[];if(!e.Properties.ManagedPolicyArns.includes(n))e.Properties.ManagedPolicyArns.push(n);return e}static addInlinePolicyToRole(e,n,r){if(!e.Properties.Policies)e.Properties.Policies=[];let i=r.map((s)=>({Effect:s.effect||"Allow",Action:s.actions,Resource:s.resources}));return e.Properties.Policies.push({PolicyName:n,PolicyDocument:{Version:"2012-10-17",Statement:i}}),e}static addInlinePolicyToUser(e,n,r){if(!e.Properties.Policies)e.Properties.Policies=[];let i=r.map((s)=>({Effect:s.effect||"Allow",Action:s.actions,Resource:s.resources}));return e.Properties.Policies.push({PolicyName:n,PolicyDocument:{Version:"2012-10-17",Statement:i}}),e}static createAccessKey(e,n){let{slug:r,environment:i,status:s="Active"}=n,a=l({slug:r,environment:i,resourceType:"access-key"}),c=o(a);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:v.Ref(e),Status:s}},logicalId:c}}static createInstanceProfile(e,n){let{slug:r,environment:i,profileName:s}=n,a=s||l({slug:r,environment:i,resourceType:"instance-profile"}),c=o(a);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:a,Roles:[v.Ref(e)]}},logicalId:c}}static ManagedPolicies={AdministratorAccess:"arn:aws:iam::aws:policy/AdministratorAccess",PowerUserAccess:"arn:aws:iam::aws:policy/PowerUserAccess",ReadOnlyAccess:"arn:aws:iam::aws:policy/ReadOnlyAccess",S3FullAccess:"arn:aws:iam::aws:policy/AmazonS3FullAccess",S3ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",DynamoDBFullAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",DynamoDBReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess",RDSFullAccess:"arn:aws:iam::aws:policy/AmazonRDSFullAccess",RDSReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess",LambdaFullAccess:"arn:aws:iam::aws:policy/AWSLambda_FullAccess",LambdaReadOnlyAccess:"arn:aws:iam::aws:policy/AWSLambda_ReadOnlyAccess",LambdaBasicExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",LambdaVPCAccessExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole",EC2FullAccess:"arn:aws:iam::aws:policy/AmazonEC2FullAccess",EC2ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess",EC2ContainerRegistryReadOnly:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",EC2ContainerRegistryPowerUser:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser",ECSTaskExecutionRole:"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",ECSFullAccess:"arn:aws:iam::aws:policy/AmazonECS_FullAccess",CloudWatchFullAccess:"arn:aws:iam::aws:policy/CloudWatchFullAccess",CloudWatchLogsFullAccess:"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess",SESFullAccess:"arn:aws:iam::aws:policy/AmazonSESFullAccess",SNSFullAccess:"arn:aws:iam::aws:policy/AmazonSNSFullAccess",SQSFullAccess:"arn:aws:iam::aws:policy/AmazonSQSFullAccess",SecretsManagerReadWrite:"arn:aws:iam::aws:policy/SecretsManagerReadWrite"};static ServicePrincipals={Lambda:"lambda.amazonaws.com",EC2:"ec2.amazonaws.com",ECS:"ecs.amazonaws.com",ECSTaskExecution:"ecs-tasks.amazonaws.com",APIGateway:"apigateway.amazonaws.com",Events:"events.amazonaws.com",States:"states.amazonaws.com",CodeBuild:"codebuild.amazonaws.com",CodeDeploy:"codedeploy.amazonaws.com",CloudFormation:"cloudformation.amazonaws.com"};static createCiCdUser(e){let{slug:n,environment:r,permissions:i,createAccessKey:s=!0}=e,a={},c=[];if(i.s3Buckets&&i.s3Buckets.length>0)c.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...i.s3Buckets,...i.s3Buckets.map((f)=>`${f}/*`)]});if(i.cloudFrontDistributions&&i.cloudFrontDistributions.length>0)c.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:i.cloudFrontDistributions});if(i.ecrRepositories&&i.ecrRepositories.length>0)c.push({sid:"ECRAccess",actions:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:GetRepositoryPolicy","ecr:DescribeRepositories","ecr:ListImages","ecr:DescribeImages","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:i.ecrRepositories}),c.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(i.ecsServices&&i.ecsServices.length>0)c.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:i.ecsServices}),c.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),c.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(i.cloudFormationStacks&&i.cloudFormationStacks.length>0)c.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:i.cloudFormationStacks});if(i.lambdaFunctions&&i.lambdaFunctions.length>0)c.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:i.lambdaFunctions});if(i.secretsManagerSecrets&&i.secretsManagerSecrets.length>0)c.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:i.secretsManagerSecrets});let{policy:u,logicalId:d}=Pe.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${n} (${r})`,statements:c});a[d]=u;let{user:m,logicalId:p}=Pe.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cicd-user"}),managedPolicyArns:[v.Ref(d)]});a[p]=m;let g,y;if(s){let f=Pe.createAccessKey(p,{slug:n,environment:r});g=f.accessKey,y=f.logicalId,a[y]=g}return{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:a}}static createCrossAccountRole(e){let{slug:n,environment:r,trustedAccountIds:i,externalId:s,permissions:a,maxSessionDuration:c=3600}=e,u={},{policy:d,logicalId:m}=Pe.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${n} (${r})`,statements:a});u[m]=d;let p=l({slug:n,environment:r,resourceType:"cross-account-role"}),g=o(p),y={};if(s)y.StringEquals={"sts:ExternalId":s};let f={Type:"AWS::IAM::Role",Properties:{RoleName:p,MaxSessionDuration:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:i.map((h)=>`arn:aws:iam::${h}:root`)},Action:"sts:AssumeRole",...Object.keys(y).length>0?{Condition:y}:{}}]},ManagedPolicyArns:[v.Ref(m)],Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Cross-Account Access"}]}};return u[g]=f,{role:f,policy:d,roleLogicalId:g,policyLogicalId:m,resources:u}}static createCliUser(e){let{slug:n,environment:r,permissions:i="readonly"}=e,s={},a=[],c=[];switch(i){case"readonly":c=[Pe.ManagedPolicies.ReadOnlyAccess];break;case"deploy":a=[{sid:"S3Deploy",actions:["s3:*"],resources:"*"},{sid:"CloudFrontDeploy",actions:["cloudfront:*"],resources:"*"},{sid:"ECSDeploy",actions:["ecs:*"],resources:"*"},{sid:"ECRDeploy",actions:["ecr:*"],resources:"*"},{sid:"LambdaDeploy",actions:["lambda:*"],resources:"*"},{sid:"CloudFormationDeploy",actions:["cloudformation:*"],resources:"*"},{sid:"IAMPassRole",actions:["iam:PassRole"],resources:"*"}];break;case"admin":c=[Pe.ManagedPolicies.AdministratorAccess];break}let u,d;if(a.length>0){let f=Pe.createPolicy({slug:n,environment:r,policyName:l({slug:n,environment:r,resourceType:"cli-policy"}),description:`CLI access policy for ${n} (${r})`,statements:a});u=f.policy,d=f.logicalId,s[d]=u,c=[v.Ref(d)]}let{user:m,logicalId:p}=Pe.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cli-user"}),managedPolicyArns:c});s[p]=m;let{accessKey:g,logicalId:y}=Pe.createAccessKey(p,{slug:n,environment:r});return s[y]=g,{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:s}}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((n)=>`${n}/*`)}],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 cs{static createRestApi(e){let{slug:n,environment:r,name:i,description:s,endpointType:a="REGIONAL",binaryMediaTypes:c,compressionSize:u}=e,d=i||l({slug:n,environment:r,resourceType:"rest-api"}),m=o(d),p={Type:"AWS::ApiGateway::RestApi",Properties:{Name:d,Description:s||`REST API for ${n} ${r}`,EndpointConfiguration:{Types:[a]},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r}]}};if(c&&c.length>0)p.Properties.BinaryMediaTypes=c;if(u!==void 0)p.Properties.MinimumCompressionSize=u;return{restApi:p,logicalId:m}}static createHttpApi(e){let{slug:n,environment:r,name:i,description:s,corsEnabled:a=!0,corsOrigins:c=["*"],corsMethods:u=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:d=["*"],corsMaxAge:m=86400,corsAllowCredentials:p=!1}=e,g=i||l({slug:n,environment:r,resourceType:"http-api"}),y=o(g),f={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:g,Description:s||`HTTP API for ${n} ${r}`,ProtocolType:"HTTP",Tags:{Name:g,Environment:r}}};if(a)f.Properties.CorsConfiguration={AllowOrigins:c,AllowMethods:u,AllowHeaders:d,MaxAge:m,AllowCredentials:p};return{httpApi:f,logicalId:y}}static createWebSocketApi(e){let{slug:n,environment:r,name:i,description:s}=e,a=i||l({slug:n,environment:r,resourceType:"ws-api"}),c=o(a);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:a,Description:s||`WebSocket API for ${n} ${r}`,ProtocolType:"WEBSOCKET",Tags:{Name:a,Environment:r}}},logicalId:c}}static createDeployment(e,n){let{slug:r,environment:i,description:s}=n,a=l({slug:r,environment:i,resourceType:"api-deployment"}),c=o(a);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:v.Ref(e),Description:s||`Deployment for ${a}`}},logicalId:c}}static createStage(e,n,r){let{slug:i,environment:s,stageName:a,description:c,cacheEnabled:u=!1,cacheSize:d="0.5",variables:m,throttling:p}=r,g=l({slug:i,environment:s,resourceType:"api-stage"}),y=o(g),f={Type:"AWS::ApiGateway::Stage",Properties:{StageName:a||s,RestApiId:v.Ref(e),DeploymentId:v.Ref(n),Description:c,CacheClusterEnabled:u,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:s}]}};if(u)f.Properties.CacheClusterSize=d;if(m)f.Properties.Variables=m;if(p)f.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:p.burstLimit,ThrottlingRateLimit:p.rateLimit}];return{stage:f,logicalId:y}}static createAuthorizer(e,n){let{slug:r,environment:i,name:s,type:a,functionArn:c,identitySource:u,userPoolArns:d,ttl:m=300}=n,p=s||l({slug:r,environment:i,resourceType:"api-authorizer"}),g=o(p),y={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:p,Type:a,RestApiId:v.Ref(e),AuthorizerResultTtlInSeconds:m}};if(a==="TOKEN"||a==="REQUEST"){if(!c)throw Error("Lambda authorizer requires functionArn");y.Properties.AuthorizerUri=c,y.Properties.IdentitySource=u||"method.request.header.Authorization"}if(a==="COGNITO_USER_POOLS"){if(!d||d.length===0)throw Error("Cognito authorizer requires userPoolArns");y.Properties.ProviderARNs=d,y.Properties.IdentitySource=u||"method.request.header.Authorization"}return{authorizer:y,logicalId:g}}static setCors(e,n={}){let{origins:r=["*"],methods:i=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:s=["*"],maxAge:a=86400,allowCredentials:c=!1}=n;return e.Properties.CorsConfiguration={AllowOrigins:r,AllowMethods:i,AllowHeaders:s,MaxAge:a,AllowCredentials:c},e}static addThrottling(e,n=5000,r=1e4){if(!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:n,ThrottlingRateLimit:r}),e}static enableCaching(e,n="0.5",r=300){if(e.Properties.CacheClusterEnabled=!0,e.Properties.CacheClusterSize=n,!e.Properties.MethodSettings)e.Properties.MethodSettings=[];return e.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:r}),e}static CacheSizes={Small:"0.5",Medium:"1.6",Large:"6.1",XLarge:"13.5",XXLarge:"28.4",XXXLarge:"58.2",Huge:"118",Massive:"237"};static ThrottlingPresets={Light:{burstLimit:100,rateLimit:50},Medium:{burstLimit:500,rateLimit:250},Heavy:{burstLimit:2000,rateLimit:1000},Default:{burstLimit:5000,rateLimit:1e4}}}class Me{static createTopic(e){let{slug:n,environment:r,topicName:i,displayName:s,encrypted:a=!1,kmsKeyId:c}=e,u=i||l({slug:n,environment:r,resourceType:"topic"}),d=o(u),m={Type:"AWS::SNS::Topic",Properties:{TopicName:u,DisplayName:s||u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(a&&c)m.Properties.KmsMasterKeyId=c;return{topic:m,logicalId:d}}static subscribe(e,n){let{slug:r,environment:i,protocol:s,endpoint:a,filterPolicy:c,rawMessageDelivery:u=!1}=n,d=l({slug:r,environment:i,resourceType:"subscription"}),m=a.replace(/[^a-zA-Z0-9]/g,""),p=m.length>12?m.slice(-12):m,g=o(`${d}-${s}-${p}`),y={Type:"AWS::SNS::Subscription",Properties:{TopicArn:v.Ref(e),Protocol:s,Endpoint:a,RawMessageDelivery:u}};if(c)y.Properties.FilterPolicy=c;return{subscription:y,logicalId:g}}static subscribeEmail(e,n,r){return Me.subscribe(e,{...r,protocol:"email",endpoint:n})}static subscribeLambda(e,n,r){return Me.subscribe(e,{...r,protocol:"lambda",endpoint:n,rawMessageDelivery:!0})}static subscribeSqs(e,n,r){return Me.subscribe(e,{...r,protocol:"sqs",endpoint:n})}static subscribeHttp(e,n,r){let i=n.startsWith("https://")?"https":"http";return Me.subscribe(e,{...r,protocol:i,endpoint:n})}static subscribeSms(e,n,r){return Me.subscribe(e,{...r,protocol:"sms",endpoint:n})}static setTopicPolicy(e,n){let{slug:r,environment:i,allowedPrincipals:s,allowedServices:a,actions:c="SNS:Publish"}=n,u=l({slug:r,environment:i,resourceType:"topic-policy"}),d=o(u),m={};if(s)m.AWS=s;if(a)m.Service=a;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[v.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:c,Resource:v.Ref(e)}]}}},logicalId:d}}static allowCloudWatchAlarms(e,n){return Me.setTopicPolicy(e,{...n,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,n){return Me.setTopicPolicy(e,{...n,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,n){return Me.setTopicPolicy(e,{...n,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(e,n){if(!e.Properties)e.Properties={};return e.Properties.KmsMasterKeyId=n,e}static addInlineSubscription(e,n,r){if(!e.Properties)e.Properties={};if(!e.Properties.Subscription)e.Properties.Subscription=[];return e.Properties.Subscription.push({Protocol:n,Endpoint:r}),e}static FilterPolicies={eventType:(e)=>({eventType:e}),status:(e)=>({status:e}),numericRange:(e,n,r)=>({[e]:[{numeric:[">=",n,"<=",r]}]}),prefix:(e,n)=>({[e]:[{prefix:n}]}),and:(...e)=>Object.assign({},...e),exists:(e,n)=>({[e]:[{exists:n}]})};static UseCases={createAlertTopic:(e)=>Me.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>Me.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>Me.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class Au{static createStateMachine(e){let{slug:n,environment:r,stateMachineName:i,type:s="STANDARD",definition:a,roleArn:c,loggingConfiguration:u,tracingConfiguration:d}=e,m=i||l({slug:n,environment:r,resourceType:"state-machine"}),p=o(m),g,y,f;if(c)f=c;else{let S=l({slug:n,environment:r,resourceType:"state-machine-role"});y=o(S),g={Type:"AWS::IAM::Role",Properties:{RoleName:S,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:S},{Key:"Environment",Value:r}]}},f=v.GetAtt(y,"Arn")}let h={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:m,StateMachineType:s,DefinitionString:JSON.stringify(a),RoleArn:f,Tags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(u)h.Properties.LoggingConfiguration={Level:u.level,IncludeExecutionData:u.includeExecutionData,Destinations:u.destinations?.map((S)=>({CloudWatchLogsLogGroup:{LogGroupArn:S}}))};if(d)h.Properties.TracingConfiguration={Enabled:d.enabled};return{stateMachine:h,logicalId:p,role:g,roleLogicalId:y}}static createLambdaTask(e,n){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:e,Payload:n?.parameters||{"Input.$":"$"}},ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createDynamoDBTask(e,n,r,i){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:n,...r},ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createSNSPublishTask(e,n,r){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:e,Message:n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createSQSSendMessageTask(e,n,r){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:e,MessageBody:n},ResultPath:r?.resultPath,Retry:r?.retry,Catch:r?.catch,Next:r?.next,End:r?.end}}static createPassState(e){return{Type:"Pass",Result:e?.result,ResultPath:e?.resultPath,Parameters:e?.parameters,Next:e?.next,End:e?.end}}static createWaitState(e){return{Type:"Wait",Seconds:e.seconds,Timestamp:e.timestamp,SecondsPath:e.secondsPath,TimestampPath:e.timestampPath,Next:e.next,End:e.end}}static createChoiceState(e,n){return{Type:"Choice",Choices:e,Default:n}}static createParallelState(e,n){return{Type:"Parallel",Branches:e,ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createMapState(e,n){return{Type:"Map",ItemsPath:n?.itemsPath||"$.items",Iterator:e,MaxConcurrency:n?.maxConcurrency,ResultPath:n?.resultPath,Retry:n?.retry,Catch:n?.catch,Next:n?.next,End:n?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(e,n){return{Type:"Fail",Error:e,Cause:n}}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,n,r,i)=>({ErrorEquals:e,IntervalSeconds:n,MaxAttempts:r,BackoffRate:i})};static CatchPolicies={all:(e,n)=>({ErrorEquals:["States.ALL"],Next:e,ResultPath:n||"$.error"}),specific:(e,n,r)=>({ErrorEquals:e,Next:n,ResultPath:r||"$.error"})};static Patterns={sequential:(e,n,r)=>{let i={};return r.forEach((s,a)=>{let c=a===r.length-1;i[s.name]={...s.state,Next:c?void 0:r[a+1].name,End:c}}),{Comment:"Sequential workflow",StartAt:r[0].name,States:i}},fanout:(e,n,r)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:r.map((i)=>i.definition),End:!0}}}),map:(e,n,r,i)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:r,MaxConcurrency:i,End:!0}}}),withErrorHandling:(e,n,r,i)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...r,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:i,Success:{Type:"Succeed"}}})}}class Gi{static createAlarm(e){let{slug:n,environment:r,alarmName:i,metricName:s,namespace:a,statistic:c="Average",period:u=300,evaluationPeriods:d=1,threshold:m,comparisonOperator:p,treatMissingData:g="notBreaching",actionsEnabled:y=!0,alarmActions:f,okActions:h,insufficientDataActions:S,dimensions:A,unit:R,datapointsToAlarm:P}=e,C=i||l({slug:n,environment:r,resourceType:"alarm"}),E=o(C),D={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:C,MetricName:s,Namespace:a,Statistic:c,Period:u,EvaluationPeriods:d,Threshold:m,ComparisonOperator:p,TreatMissingData:g,ActionsEnabled:y}};if(f&&f.length>0)D.Properties.AlarmActions=f;if(h&&h.length>0)D.Properties.OKActions=h;if(S&&S.length>0)D.Properties.InsufficientDataActions=S;if(A)D.Properties.Dimensions=Object.entries(A).map(([x,L])=>({Name:x,Value:L}));if(R)D.Properties.Unit=R;if(P!==void 0)D.Properties.DatapointsToAlarm=P;return{alarm:D,logicalId:E}}static createCompositeAlarm(e){let{slug:n,environment:r,alarmName:i,alarmRule:s,actionsEnabled:a=!0,alarmActions:c,okActions:u,insufficientDataActions:d}=e,m=i||l({slug:n,environment:r,resourceType:"composite-alarm"}),p=o(m),g={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:m,AlarmRule:s,ActionsEnabled:a}};if(c&&c.length>0)g.Properties.AlarmActions=c;if(u&&u.length>0)g.Properties.OKActions=u;if(d&&d.length>0)g.Properties.InsufficientDataActions=d;return{alarm:g,logicalId:p}}static createDashboard(e){let{slug:n,environment:r,dashboardName:i,widgets:s}=e,a=i||l({slug:n,environment:r,resourceType:"dashboard"}),c=o(a),u={widgets:s.map((m)=>({type:m.type,x:m.x,y:m.y,width:m.width,height:m.height,properties:m.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:a,DashboardBody:JSON.stringify(u)}},logicalId:c}}static createLogGroup(e){let{slug:n,environment:r,logGroupName:i,retentionInDays:s,kmsKeyId:a}=e,c=i||l({slug:n,environment:r,resourceType:"log-group"}),u=o(c),d={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:c}};if(s!==void 0)d.Properties.RetentionInDays=s;if(a)d.Properties.KmsKeyId=a;return{logGroup:d,logicalId:u}}static createLogStream(e,n){let{slug:r,environment:i,logStreamName:s}=n,a=s||l({slug:r,environment:i,resourceType:"log-stream"}),c=o(a);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:v.Ref(e),LogStreamName:a}},logicalId:c}}static createMetricFilter(e,n){let{slug:r,environment:i,filterName:s,filterPattern:a,metricTransformations:c}=n,u=s||l({slug:r,environment:i,resourceType:"metric-filter"}),d=o(u);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:v.Ref(e),FilterPattern:a,MetricTransformations:c.map((p)=>({MetricName:p.metricName,MetricNamespace:p.metricNamespace,MetricValue:p.metricValue,DefaultValue:p.defaultValue,Unit:p.unit}))}},logicalId:d}}static AlarmTypes={highCpu:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:s?[s]:void 0}),highMemory:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:s?[s]:void 0}),highDisk:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:s?[s]:void 0}),lambdaErrors:(e,n,r,i=5,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:s?[s]:void 0}),lambdaThrottles:(e,n,r,i=10,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:r},alarmActions:s?[s]:void 0}),apiGateway5xxErrors:(e,n,r,i=10,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:s?[s]:void 0}),apiGateway4xxErrors:(e,n,r,i=50,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:r},alarmActions:s?[s]:void 0}),dynamoDBThrottles:(e,n,r,i=5,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:r},alarmActions:s?[s]:void 0}),rdsCpu:(e,n,r,i=80,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:s?[s]:void 0}),rdsFreeStorage:(e,n,r,i=5368709120,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:r},alarmActions:s?[s]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,n,r,i=100,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:r},alarmActions:s?[s]:void 0}),albUnhealthyTargets:(e,n,r,i,s=1,a)=>({slug:e,environment:n,alarmName:`${e}-${n}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:s,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:r,TargetGroup:i},alarmActions:a?[a]:void 0}),sesBounceRate:(e,n,r=5,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),sesComplaintRate:(e,n,r=0.1,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:r/100,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),smsDeliveryFailure:(e,n,r,i=10,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:r},alarmActions:s?[s]:void 0}),smsSpendLimit:(e,n,r=100,i)=>({slug:e,environment:n,alarmName:`${e}-${n}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:r,comparisonOperator:"GreaterThanThreshold",alarmActions:i?[i]:void 0}),connectMissedCalls:(e,n,r,i=5,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:i,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:r},alarmActions:s?[s]:void 0})};static DashboardWidgets={metric:(e,n,r,i,s,a)=>({type:"metric",x:e,y:n,width:r,height:i,properties:{metrics:s,title:a||"Metrics",region:"us-east-1",period:300}}),text:(e,n,r,i,s)=>({type:"text",x:e,y:n,width:r,height:i,properties:{markdown:s}}),log:(e,n,r,i,s,a)=>({type:"log",x:e,y:n,width:r,height:i,properties:{query:`SOURCE '${s.join("' | SOURCE '")}'
|
|
2275
2275
|
| fields @timestamp, @message
|
|
2276
2276
|
| sort @timestamp desc
|
|
2277
2277
|
| limit 20`,region:"us-east-1",title:a||"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,n)=>`{ $.${e} = "${n}" }`,httpStatus:(e)=>`[..., status_code = ${e}, ...]`,http4xx:"[..., status_code = 4*, ...]",http5xx:"[..., status_code = 5*, ...]"};static createApplicationDashboard(e){let{slug:n,environment:r,region:i="us-east-1",components:s={}}=e,a=[],c=0;if(a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:`# ${n.toUpperCase()} Dashboard (${r})`}}),c+=1,s.ec2InstanceIds&&s.ec2InstanceIds.length>0)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## EC2 Instances"}}),c+=1,a.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:i,metrics:s.ec2InstanceIds.map((u)=>["AWS/EC2","CPUUtilization","InstanceId",u]),period:300,stat:"Average"}}),a.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Network Traffic",region:i,metrics:[...s.ec2InstanceIds.flatMap((u)=>[["AWS/EC2","NetworkIn","InstanceId",u,{label:`${u} In`}],["AWS/EC2","NetworkOut","InstanceId",u,{label:`${u} Out`}]])],period:300,stat:"Sum"}}),a.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Status Checks",region:i,metrics:s.ec2InstanceIds.map((u)=>["AWS/EC2","StatusCheckFailed","InstanceId",u]),period:60,stat:"Maximum"}}),c+=6;if(s.lambdaFunctionNames&&s.lambdaFunctionNames.length>0)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Lambda Functions"}}),c+=1,a.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"Invocations",region:i,metrics:s.lambdaFunctionNames.map((u)=>["AWS/Lambda","Invocations","FunctionName",u]),period:300,stat:"Sum"}}),a.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Duration",region:i,metrics:s.lambdaFunctionNames.map((u)=>["AWS/Lambda","Duration","FunctionName",u]),period:300,stat:"Average"}}),a.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Errors",region:i,metrics:s.lambdaFunctionNames.map((u)=>["AWS/Lambda","Errors","FunctionName",u]),period:300,stat:"Sum"}}),c+=6;if(s.ecsClusterName&&s.ecsServiceName)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## ECS Service"}}),c+=1,a.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:i,metrics:[["AWS/ECS","CPUUtilization","ClusterName",s.ecsClusterName,"ServiceName",s.ecsServiceName]],period:300,stat:"Average"}}),a.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Memory Utilization",region:i,metrics:[["AWS/ECS","MemoryUtilization","ClusterName",s.ecsClusterName,"ServiceName",s.ecsServiceName]],period:300,stat:"Average"}}),a.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Running Tasks",region:i,metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",s.ecsClusterName,"ServiceName",s.ecsServiceName]],period:60,stat:"Average"}}),c+=6;if(s.albName)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Application Load Balancer"}}),c+=1,a.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"Request Count",region:i,metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",s.albName]],period:60,stat:"Sum"}}),a.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Response Time",region:i,metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",s.albName]],period:60,stat:"Average"}}),a.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"HTTP Errors",region:i,metrics:[["AWS/ApplicationELB","HTTPCode_Target_4XX_Count","LoadBalancer",s.albName,{label:"4XX"}],["AWS/ApplicationELB","HTTPCode_Target_5XX_Count","LoadBalancer",s.albName,{label:"5XX"}]],period:60,stat:"Sum"}}),c+=6;if(s.rdsInstanceId)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## RDS Database"}}),c+=1,a.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:i,metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",s.rdsInstanceId]],period:300,stat:"Average"}}),a.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Database Connections",region:i,metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",s.rdsInstanceId]],period:60,stat:"Sum"}}),a.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Free Storage Space",region:i,metrics:[["AWS/RDS","FreeStorageSpace","DBInstanceIdentifier",s.rdsInstanceId]],period:300,stat:"Average"}}),c+=6;if(s.sqsQueueNames&&s.sqsQueueNames.length>0)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## SQS Queues"}}),c+=1,a.push({type:"metric",x:0,y:c,width:12,height:6,properties:{title:"Messages Visible",region:i,metrics:s.sqsQueueNames.map((u)=>["AWS/SQS","ApproximateNumberOfMessagesVisible","QueueName",u]),period:60,stat:"Sum"}}),a.push({type:"metric",x:12,y:c,width:12,height:6,properties:{title:"Message Age",region:i,metrics:s.sqsQueueNames.map((u)=>["AWS/SQS","ApproximateAgeOfOldestMessage","QueueName",u]),period:60,stat:"Maximum"}}),c+=6;if(s.logGroupNames&&s.logGroupNames.length>0)a.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Application Logs"}}),c+=1,a.push({type:"log",x:0,y:c,width:24,height:6,properties:{query:`SOURCE '${s.logGroupNames.join("' | SOURCE '")}'
|
|
2278
2278
|
| fields @timestamp, @message
|
|
2279
2279
|
| filter @message like /ERROR|WARN|Exception/
|
|
2280
2280
|
| sort @timestamp desc
|
|
2281
|
-
| limit 50`,region:i,title:"Recent Errors and Warnings"}}),c+=6;return zi.createDashboard({slug:n,environment:r,widgets:a})}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((n,r)=>({type:"metric",x:r%3*8,y:7+Math.floor(r/3)*6,width:8,height:6,properties:{title:`${n} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",n],["AWS/Lambda","Duration","FunctionName",n],["AWS/Lambda","Errors","FunctionName",n]],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:n,namespace:r,threshold:i,comparisonOperator:s="GreaterThanThreshold",evaluationPeriods:a=1,period:c=300,statistic:u="Average",treatMissingData:d="missing"}=e;return{MetricName:n,Namespace:r,Threshold:i,ComparisonOperator:s,EvaluationPeriods:a,Period:c,Statistic:u,TreatMissingData:d}},namespaces:{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",sqs:"AWS/SQS",sns:"AWS/SNS",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apiGateway:"AWS/ApiGateway",dynamodb:"AWS/DynamoDB",elasticache:"AWS/ElastiCache"},comparisonOperators:{greaterThan:"GreaterThanThreshold",greaterOrEqual:"GreaterThanOrEqualToThreshold",lessThan:"LessThanThreshold",lessOrEqual:"LessThanOrEqualToThreshold"},metrics:{ec2:{cpu:{metricName:"CPUUtilization",namespace:"AWS/EC2"},networkIn:{metricName:"NetworkIn",namespace:"AWS/EC2"},networkOut:{metricName:"NetworkOut",namespace:"AWS/EC2"},statusCheck:{metricName:"StatusCheckFailed",namespace:"AWS/EC2"}},ecs:{cpu:{metricName:"CPUUtilization",namespace:"AWS/ECS"},memory:{metricName:"MemoryUtilization",namespace:"AWS/ECS"}},lambda:{invocations:{metricName:"Invocations",namespace:"AWS/Lambda"},errors:{metricName:"Errors",namespace:"AWS/Lambda"},duration:{metricName:"Duration",namespace:"AWS/Lambda"},throttles:{metricName:"Throttles",namespace:"AWS/Lambda"},concurrentExecutions:{metricName:"ConcurrentExecutions",namespace:"AWS/Lambda"}},rds:{cpu:{metricName:"CPUUtilization",namespace:"AWS/RDS"},connections:{metricName:"DatabaseConnections",namespace:"AWS/RDS"},freeStorage:{metricName:"FreeStorageSpace",namespace:"AWS/RDS"},readLatency:{metricName:"ReadLatency",namespace:"AWS/RDS"},writeLatency:{metricName:"WriteLatency",namespace:"AWS/RDS"}},alb:{requestCount:{metricName:"RequestCount",namespace:"AWS/ApplicationELB"},responseTime:{metricName:"TargetResponseTime",namespace:"AWS/ApplicationELB"},httpCode4xx:{metricName:"HTTPCode_Target_4XX_Count",namespace:"AWS/ApplicationELB"},httpCode5xx:{metricName:"HTTPCode_Target_5XX_Count",namespace:"AWS/ApplicationELB"},healthyHosts:{metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB"}},sqs:{messagesVisible:{metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS"},messagesDelayed:{metricName:"ApproximateNumberOfMessagesDelayed",namespace:"AWS/SQS"},messageAge:{metricName:"ApproximateAgeOfOldestMessage",namespace:"AWS/SQS"}}},presets:{highCpu:(e=80)=>({metricName:"CPUUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(e=80)=>({metricName:"MemoryUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(e=10)=>({metricName:"Errors",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(e=5000)=>({metricName:"Duration",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(e=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(e=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(e=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class Pe{static createUserPool(e){let{slug:n,environment:r,userPoolName:i,aliasAttributes:s,autoVerifiedAttributes:a,passwordPolicy:c,mfaConfiguration:u,emailConfiguration:d,smsConfiguration:m,lambdaTriggers:p,userPoolAddOns:g,accountRecoverySetting:y}=e,f=i||l({slug:n,environment:r,resourceType:"user-pool"}),h=o(f),S={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:f,Policies:c?{PasswordPolicy:{MinimumLength:c.minimumLength,RequireLowercase:c.requireLowercase,RequireUppercase:c.requireUppercase,RequireNumbers:c.requireNumbers,RequireSymbols:c.requireSymbols,TemporaryPasswordValidityDays:c.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:u,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(s&&s.length>0)S.Properties.UsernameAttributes=s;if(a&&a.length>0)S.Properties.AutoVerifiedAttributes=a;if(d)S.Properties.EmailConfiguration={EmailSendingAccount:d.emailSendingAccount,From:d.from,ReplyToEmailAddress:d.replyToEmailAddress,SourceArn:d.sourceArn,ConfigurationSet:d.configurationSet};if(m)S.Properties.SmsConfiguration={ExternalId:m.externalId,SnsCallerArn:m.snsCallerArn};if(p)S.Properties.LambdaConfig={PreSignUp:p.preSignUp,PostConfirmation:p.postConfirmation,PreAuthentication:p.preAuthentication,PostAuthentication:p.postAuthentication,CustomMessage:p.customMessage,DefineAuthChallenge:p.defineAuthChallenge,CreateAuthChallenge:p.createAuthChallenge,VerifyAuthChallengeResponse:p.verifyAuthChallengeResponse,PreTokenGeneration:p.preTokenGeneration,UserMigration:p.userMigration};if(g)S.Properties.UserPoolAddOns={AdvancedSecurityMode:g.advancedSecurityMode};if(y)S.Properties.AccountRecoverySetting={RecoveryMechanisms:y.recoveryMechanisms};return{userPool:S,logicalId:h}}static createUserPoolClient(e,n){let{slug:r,environment:i,clientName:s,generateSecret:a=!1,refreshTokenValidity:c,accessTokenValidity:u,idTokenValidity:d,tokenValidityUnits:m,readAttributes:p,writeAttributes:g,explicitAuthFlows:y,preventUserExistenceErrors:f,enableTokenRevocation:h,callbackURLs:S,logoutURLs:A,allowedOAuthFlows:R,allowedOAuthScopes:P,allowedOAuthFlowsUserPoolClient:C,supportedIdentityProviders:E}=n,D=s||l({slug:r,environment:i,resourceType:"user-pool-client"}),x=o(D);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:D,UserPoolId:v.Ref(e),GenerateSecret:a,RefreshTokenValidity:c,AccessTokenValidity:u,IdTokenValidity:d,TokenValidityUnits:m,ReadAttributes:p,WriteAttributes:g,ExplicitAuthFlows:y,PreventUserExistenceErrors:f,EnableTokenRevocation:h,CallbackURLs:S,LogoutURLs:A,AllowedOAuthFlows:R,AllowedOAuthScopes:P,AllowedOAuthFlowsUserPoolClient:C,SupportedIdentityProviders:E}},logicalId:x}}static createUserPoolDomain(e,n){let{slug:r,environment:i,domain:s,customDomainConfig:a}=n,c=l({slug:r,environment:i,resourceType:"user-pool-domain"}),u=o(c);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:s,UserPoolId:v.Ref(e),CustomDomainConfig:a}},logicalId:u}}static createIdentityPool(e){let{slug:n,environment:r,identityPoolName:i,allowUnauthenticatedIdentities:s=!1,cognitoIdentityProviders:a,supportedLoginProviders:c,samlProviderARNs:u,openIdConnectProviderARNs:d}=e,m=i||l({slug:n,environment:r,resourceType:"identity-pool"}),p=o(m);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:m,AllowUnauthenticatedIdentities:s,CognitoIdentityProviders:a,SupportedLoginProviders:c,SamlProviderARNs:u,OpenIdConnectProviderARNs:d}},logicalId:p}}static createIdentityPoolRoleAttachment(e,n){let{slug:r,environment:i,authenticatedRole:s,unauthenticatedRole:a,roleMappings:c}=n,u=l({slug:r,environment:i,resourceType:"identity-pool-role-attachment"}),d=o(u),m={authenticated:s};if(a)m.unauthenticated=a;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:v.Ref(e),Roles:m,RoleMappings:c}},logicalId:d}}static createAuthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,s=l({slug:n,environment:r,resourceType:"cognito-authenticated-role"}),a=o(s);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":v.Ref(i)},"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:s},{Key:"Environment",Value:r}]}},logicalId:a}}static createUnauthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,s=l({slug:n,environment:r,resourceType:"cognito-unauthenticated-role"}),a=o(s);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":v.Ref(i)},"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:s},{Key:"Environment",Value:r}]}},logicalId:a}}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,n,r)=>{let{userPool:i,logicalId:s}=Pe.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Pe.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:a,logicalId:c}=Pe.createUserPoolClient(s,{slug:e,environment:n,explicitAuthFlows:[...Pe.AuthFlows.standard],callbackURLs:[r],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Pe.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:i,poolId:s,client:a,clientId:c}},mobileApp:(e,n)=>{let{userPool:r,logicalId:i}=Pe.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Pe.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:s,logicalId:a}=Pe.createUserPoolClient(i,{slug:e,environment:n,explicitAuthFlows:[...Pe.AuthFlows.standard]}),{identityPool:c,logicalId:u}=Pe.createIdentityPool({slug:e,environment:n,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:v.Ref(a),ProviderName:v.GetAtt(i,"ProviderName")}]}),{role:d,logicalId:m}=Pe.createAuthenticatedRole({slug:e,environment:n,identityPoolLogicalId:u}),{attachment:p,logicalId:g}=Pe.createIdentityPoolRoleAttachment(u,{slug:e,environment:n,authenticatedRole:v.GetAtt(m,"Arn")});return{userPool:r,poolId:i,client:s,clientId:a,identityPool:c,identityPoolId:u,authRole:d,authRoleId:m,attachment:p,attachmentId:g}}}}import{createHash as $r}from"node:crypto";import{copyFileSync as Br,existsSync as bt,readdirSync as _r,readFileSync as Xe,statSync as Wr,writeFileSync as et}from"node:fs";import{basename as Ur,dirname as cn,extname as ln,join as Ve}from"node:path";class De{static createApplication(e){let{slug:n,environment:r,applicationName:i,computePlatform:s}=e,a=i||l({slug:n,environment:r,resourceType:"deploy-app"}),c=o(a);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:a,ComputePlatform:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r}]}},logicalId:c}}static createDeploymentGroup(e,n){let{slug:r,environment:i,deploymentGroupName:s,serviceRoleArn:a,autoScalingGroups:c,ec2TagFilters:u,deploymentConfigName:d,autoRollbackConfiguration:m,alarmConfiguration:p,loadBalancerInfo:g,blueGreenDeploymentConfiguration:y}=n,f=s||l({slug:r,environment:i,resourceType:"deploy-group"}),h=o(f);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:v.Ref(e),DeploymentGroupName:f,ServiceRoleArn:a,AutoScalingGroups:c,Ec2TagFilters:u?.map((A)=>({Key:A.key,Value:A.value,Type:A.type})),DeploymentConfigName:d,AutoRollbackConfiguration:m?{Enabled:m.enabled,Events:m.events}:void 0,AlarmConfiguration:p?{Enabled:p.enabled,Alarms:p.alarms?.map((A)=>({Name:A.name})),IgnorePollAlarmFailure:p.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:g?{TargetGroupInfoList:g.targetGroupInfoList?.map((A)=>({Name:A.name})),ElbInfoList:g.elbInfoList?.map((A)=>({Name:A.name}))}:void 0,BlueGreenDeploymentConfiguration:y?{TerminateBlueInstancesOnDeploymentSuccess:y.terminateBlueInstancesOnDeploymentSuccess?{Action:y.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:y.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:y.deploymentReadyOption?{ActionOnTimeout:y.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:y.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:y.greenFleetProvisioningOption?{Action:y.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:i}]}},logicalId:h}}static createDeploymentConfig(e){let{slug:n,environment:r,deploymentConfigName:i,minimumHealthyHosts:s,trafficRoutingConfig:a}=e,c=i||l({slug:n,environment:r,resourceType:"deploy-config"}),u=o(c);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:c,MinimumHealthyHosts:s?{Type:s.type,Value:s.value}:void 0,TrafficRoutingConfig:a?{Type:a.type,TimeBasedCanary:a.timeBasedCanary?{CanaryPercentage:a.timeBasedCanary.canaryPercentage,CanaryInterval:a.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:a.timeBasedLinear?{LinearPercentage:a.timeBasedLinear.linearPercentage,LinearInterval:a.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:u}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(e,n)=>({type:e,value:n})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,n)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:n}}),linear:(e,n)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:n}})};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,n,r,i)=>{let{application:s,logicalId:a}=De.createApplication({slug:e,environment:n,computePlatform:"Server"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(a,{slug:e,environment:n,serviceRoleArn:r,autoScalingGroups:i,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:s,appId:a,deploymentGroup:c,groupId:u}},lambdaCanaryDeployment:(e,n,r,i=10,s=5)=>{let{application:a,logicalId:c}=De.createApplication({slug:e,environment:n,computePlatform:"Lambda"}),{deploymentConfig:u,logicalId:d}=De.createDeploymentConfig({slug:e,environment:n,trafficRoutingConfig:De.TrafficRouting.canary(i,s)}),{deploymentGroup:m,logicalId:p}=De.createDeploymentGroup(c,{slug:e,environment:n,serviceRoleArn:r,deploymentConfigName:v.Ref(d),autoRollbackConfiguration:De.RollbackConfigs.onAlarmOrFailure()});return{application:a,appId:c,deploymentConfig:u,configId:d,deploymentGroup:m,groupId:p}},ecsBlueGreenDeployment:(e,n,r,i)=>{let{application:s,logicalId:a}=De.createApplication({slug:e,environment:n,computePlatform:"ECS"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(a,{slug:e,environment:n,serviceRoleArn:r,loadBalancerInfo:{targetGroupInfoList:[{name:i}]},blueGreenDeploymentConfiguration:De.BlueGreenConfigs.standard(),autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:s,appId:a,deploymentGroup:c,groupId:u}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,n=5)=>({type:"canary",canaryPercentage:e,canaryInterval:n}),allAtOnce:()=>({type:"all-at-once"})}}class oe{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,n="md5"){let r=Xe(e);return $r(n).update(r).digest("hex")}static computeShortHash(e){return oe.computeFileHash(e).slice(0,8)}static getContentType(e){let n=ln(e).toLowerCase();return oe.ContentTypes[n]||"application/octet-stream"}static shouldHashFile(e,n){return![...oe.NoHashPatterns,...n||[]].some((i)=>i.test(e))}static generateHashedFilename(e,n){let r=ln(e),i=Ur(e,r),s=cn(e);if(s===".")return`${i}.${n}${r}`;return Ve(s,`${i}.${n}${r}`)}static collectFiles(e,n){let r=[],i=n||e;if(!bt(e))return r;let s=_r(e,{withFileTypes:!0});for(let a of s){let c=Ve(e,a.name);if(a.isDirectory())r.push(...oe.collectFiles(c,i));else if(a.isFile())r.push(c)}return r}static hashDirectory(e){let{sourceDir:n,outputDir:r,excludePatterns:i=[],hashAlgorithm:s="md5",copyUnhashed:a=!0}=e,c=oe.collectFiles(n),u=[],d={};for(let p of c){let g=p.replace(n,"").replace(/^[/\\]/,""),y=oe.shouldHashFile(g,i),f=Wr(p),h=y?oe.computeFileHash(p,s).slice(0,8):"",S=y?oe.generateHashedFilename(g,h):g,A={originalPath:g,hashedPath:S,hash:h,size:f.size,contentType:oe.getContentType(p)};if(u.push(A),d[g]=S,r){let R=Ve(r,S),P=cn(R);if(!bt(P)){let{mkdirSync:C}=Gr("node:fs");C(P,{recursive:!0})}if(y||a)Br(p,R)}}let m={version:"1.0",timestamp:new Date().toISOString(),assets:u,hashMap:d};if(r){let p=Ve(r,"asset-manifest.json");et(p,JSON.stringify(m,null,2))}return m}static getInvalidationPaths(e,n){let r=[];if(!e)return["/*"];let i=e.hashMap,s=n.hashMap;for(let[a,c]of Object.entries(s)){let u=i[a];if(!u||u!==c){if(r.push(`/${a}`),u&&u!==c)r.push(`/${u}`)}}for(let[a,c]of Object.entries(i))if(!s[a])r.push(`/${a}`),r.push(`/${c}`);if(r.length>100)return["/*"];return[...new Set(r)]}static updateHtmlReferences(e){let{htmlDir:n,manifest:r,basePath:i=""}=e,s=oe.collectFiles(n).filter((a)=>a.endsWith(".html")||a.endsWith(".htm"));for(let a of s){let c=Xe(a,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=[new RegExp(`(src|href)=["']${i}/?${oe.escapeRegExp(u)}["']`,"g"),new RegExp(`url\\(["']?${i}/?${oe.escapeRegExp(u)}["']?\\)`,"g")];for(let p of m)c=c.replace(p,(g)=>g.replace(u,d))}et(a,c)}}static updateCssReferences(e){let{cssDir:n,manifest:r,basePath:i=""}=e,s=oe.collectFiles(n).filter((a)=>a.endsWith(".css"));for(let a of s){let c=Xe(a,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=new RegExp(`url\\(["']?${i}/?${oe.escapeRegExp(u)}["']?\\)`,"g");c=c.replace(m,`url(${i}/${d})`)}et(a,c)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:n,keyPrefix:r="",excludePatterns:i=[],cacheControl:s={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return oe.hashDirectory({sourceDir:n,excludePatterns:i}).assets.map((c)=>{let u=c.hash!=="",d=c.contentType==="text/html",m=s.unhashed||"public, max-age=3600";if(d)m=s.html||"public, max-age=0, must-revalidate";else if(u)m=s.hashed||"public, max-age=31536000, immutable";return{localPath:Ve(n,c.originalPath),s3Key:r?`${r}/${c.hashedPath}`:c.hashedPath,contentType:c.contentType,cacheControl:m,hash:c.hash}})}static compareManifests(e,n){let r={added:[],removed:[],changed:[],unchanged:[]},i=new Set(Object.keys(e.hashMap)),s=new Set(Object.keys(n.hashMap));for(let a of s)if(!i.has(a))r.added.push(a);for(let a of i)if(!s.has(a))r.removed.push(a);for(let a of s)if(i.has(a))if(e.hashMap[a]!==n.hashMap[a])r.changed.push(a);else r.unchanged.push(a);return r}static loadManifest(e){if(!bt(e))return null;try{let n=Xe(e,"utf-8");return JSON.parse(n)}catch{return null}}static saveManifest(e,n){et(n,JSON.stringify(e,null,2))}}class Hi{static createSecret(e){let{slug:n,environment:r,secretName:i,description:s,secretString:a,kmsKeyId:c,tags:u}=e,d=i||l({slug:n,environment:r,resourceType:"secret"}),m=o(d),p={Type:"AWS::SecretsManager::Secret",Properties:{Name:d,Description:s,SecretString:a,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},...u?Object.entries(u).map(([g,y])=>({Key:g,Value:y})):[]]}};if(c)p.Properties.KmsKeyId=c;return{secret:p,logicalId:m}}static createGeneratedSecret(e){let{slug:n,environment:r,secretName:i,description:s,excludeCharacters:a,excludeLowercase:c,excludeNumbers:u,excludePunctuation:d,excludeUppercase:m,passwordLength:p,requireEachIncludedType:g,kmsKeyId:y,tags:f}=e,h=i||l({slug:n,environment:r,resourceType:"secret"}),S=o(h),A={Type:"AWS::SecretsManager::Secret",Properties:{Name:h,Description:s,GenerateSecretString:{ExcludeCharacters:a,ExcludeLowercase:c,ExcludeNumbers:u,ExcludePunctuation:d,ExcludeUppercase:m,PasswordLength:p||32,RequireEachIncludedType:g!==!1},Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r},...f?Object.entries(f).map(([R,P])=>({Key:R,Value:P})):[]]}};if(y)A.Properties.KmsKeyId=y;return{secret:A,logicalId:S}}static createDatabaseSecret(e){let{slug:n,environment:r,secretName:i,username:s,dbname:a,engine:c,host:u,port:d,kmsKeyId:m}=e,p=i||l({slug:n,environment:r,resourceType:"db-secret"}),g=o(p),y={username:s};if(a)y.dbname=a;if(c)y.engine=c;if(u)y.host=u;if(d)y.port=d;let f={Type:"AWS::SecretsManager::Secret",Properties:{Name:p,Description:`Database credentials for ${s}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(y),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Type",Value:"database"}]}};if(m)f.Properties.KmsKeyId=m;return{secret:f,logicalId:g}}static attachToDatabase(e){let{slug:n,environment:r,secretId:i,targetId:s,targetType:a}=e,c=l({slug:n,environment:r,resourceType:"secret-attachment"}),u=o(c);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:i,TargetId:s,TargetType:a}},logicalId:u}}static enableRotation(e){let{slug:n,environment:r,secretId:i,rotationLambdaArn:s,automaticallyAfterDays:a,rotationType:c,kmsKeyArn:u,vpcSecurityGroupIds:d,vpcSubnetIds:m}=e,p=l({slug:n,environment:r,resourceType:"secret-rotation"}),g=o(p),y={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:i,RotationRules:{AutomaticallyAfterDays:a||30}}};if(s)y.Properties.RotationLambdaARN=s;else if(c)y.Properties.HostedRotationLambda={RotationType:c,KmsKeyArn:u,VpcSecurityGroupIds:d,VpcSubnetIds:m};return{rotation:y,logicalId:g}}static SecretTypes={apiKey:(e,n,r)=>Hi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-${r}-api-key`,description:`API key for ${r}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,n,r)=>Hi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-${r}-oauth-secret`,description:`OAuth client secret for ${r}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,n)=>Hi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,n)=>Hi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-encryption-key`,description:"Data encryption key",passwordLength:64,excludeCharacters:"+/=",excludePunctuation:!0})};static RotationTypes={MySQLSingleUser:"MySQLSingleUser",MySQLMultiUser:"MySQLMultiUser",PostgreSQLSingleUser:"PostgreSQLSingleUser",PostgreSQLMultiUser:"PostgreSQLMultiUser",OracleSingleUser:"OracleSingleUser",OracleMultiUser:"OracleMultiUser",MariaDBSingleUser:"MariaDBSingleUser",MariaDBMultiUser:"MariaDBMultiUser",SQLServerSingleUser:"SQLServerSingleUser",SQLServerMultiUser:"SQLServerMultiUser",RedshiftSingleUser:"RedshiftSingleUser",RedshiftMultiUser:"RedshiftMultiUser",MongoDBSingleUser:"MongoDBSingleUser",MongoDBMultiUser:"MongoDBMultiUser"}}class X{static createParameter(e){let{slug:n,environment:r,parameterName:i,value:s,type:a="String",description:c,tier:u="Standard",tags:d}=e,m=i||l({slug:n,environment:r,resourceType:"parameter"}),p=o(m);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${n}/${r}/${m}`,Type:a,Value:s,Description:c,Tier:u,Tags:{Name:m,Environment:r,...d}}},logicalId:p}}static createString(e,n,r,i,s){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"String",description:s})}static createSecureString(e,n,r,i,s){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"SecureString",description:s})}static createStringList(e,n,r,i,s){return X.createParameter({slug:e,environment:n,parameterName:r,value:i.join(","),type:"StringList",description:s})}static Parameters={databaseUrl:(e,n,r)=>X.createSecureString(e,n,"database-url",r,"Database connection URL"),apiEndpoint:(e,n,r)=>X.createString(e,n,"api-endpoint",r,"API endpoint URL"),appVersion:(e,n,r)=>X.createString(e,n,"app-version",r,"Application version"),featureFlags:(e,n,r)=>X.createStringList(e,n,"feature-flags",r,"Enabled feature flags"),apiKey:(e,n,r,i)=>X.createSecureString(e,n,`${r}-api-key`,i,`API key for ${r}`),oauthCredentials:(e,n,r,i)=>{let s=X.createString(e,n,"oauth-client-id",r,"OAuth client ID"),a=X.createSecureString(e,n,"oauth-client-secret",i,"OAuth client secret");return{clientId:s,clientSecret:a}},smtpCredentials:(e,n,r,i,s,a)=>{let c=X.createString(e,n,"smtp-username",r,"SMTP username"),u=X.createSecureString(e,n,"smtp-password",i,"SMTP password"),d=X.createString(e,n,"smtp-host",s,"SMTP host"),m=X.createString(e,n,"smtp-port",a.toString(),"SMTP port");return{username:c,password:u,host:d,port:m}},redisUrl:(e,n,r)=>X.createSecureString(e,n,"redis-url",r,"Redis connection URL"),s3Bucket:(e,n,r)=>X.createString(e,n,"s3-bucket",r,"S3 bucket name"),cloudFrontDistribution:(e,n,r)=>X.createString(e,n,"cloudfront-distribution-id",r,"CloudFront distribution ID")}}class Zt{static createDomain(e){let{slug:n,environment:r,domainName:i,engineVersion:s="OpenSearch_2.11",instanceType:a="t3.small.search",instanceCount:c=1,volumeSize:u=10,volumeType:d="gp3",dedicatedMaster:m=!1,dedicatedMasterType:p,dedicatedMasterCount:g=3,multiAz:y=!1,availabilityZoneCount:f=2,vpc:h,encryption:S,enforceHttps:A=!0,tlsSecurityPolicy:R="Policy-Min-TLS-1-2-2019-07",advancedSecurity:P,autoSnapshotHour:C=0,autoTune:E=!0,tags:D={}}=e,x=i||l({slug:n,environment:r,resourceType:"search"}),L=o(x);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:x,EngineVersion:s,ClusterConfig:{InstanceType:a,InstanceCount:c,DedicatedMasterEnabled:m,...m&&{DedicatedMasterType:p||a,DedicatedMasterCount:g},ZoneAwarenessEnabled:y,...y&&{ZoneAwarenessConfig:{AvailabilityZoneCount:f}}},EBSOptions:{EBSEnabled:!0,VolumeType:d,VolumeSize:u},DomainEndpointOptions:{EnforceHTTPS:A,TLSSecurityPolicy:R},SnapshotOptions:{AutomatedSnapshotStartHour:C},...h&&{VPCOptions:{SubnetIds:h.subnetIds,SecurityGroupIds:h.securityGroupIds}},...S&&{EncryptionAtRestOptions:{Enabled:S.atRest??!0,...S.kmsKeyId&&{KmsKeyId:S.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:S.nodeToNode??!0}},...P&&{AdvancedSecurityOptions:{Enabled:P.enabled,InternalUserDatabaseEnabled:P.internalUserDatabase??!0,...P.masterUserName&&P.masterUserPassword&&{MasterUserOptions:{MasterUserName:P.masterUserName,MasterUserPassword:P.masterUserPassword}},...P.masterUserArn&&{MasterUserOptions:{MasterUserARN:P.masterUserArn}}}},...E&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:x},{Key:"Environment",Value:r},...Object.entries(D).map(([O,F])=>({Key:O,Value:F}))]}},logicalId:L}}static createAccessPolicy(e,n){let{ipAddresses:r,iamPrincipalArns:i,allowAll:s,vpcEndpoint:a}=n;if(s)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let c=[];if(i&&i.length>0)c.push({Effect:"Allow",Principal:{AWS:i},Action:"es:*",Resource:e});if(r&&r.length>0)c.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e,Condition:{IpAddress:{"aws:SourceIp":r}}});if(a)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};return{Version:"2012-10-17",Statement:c}}static DomainPresets={development:(e,n)=>Zt.createDomain({slug:e,environment:n,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,n,r)=>Zt.createDomain({slug:e,environment:n,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(e,n)=>Zt.createDomain({slug:e,environment:n,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,n,r)=>Zt.createDomain({slug:e,environment:n,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!1},autoTune:!0})};static InstanceTypes={"t3.small.search":"t3.small.search","t3.medium.search":"t3.medium.search","m6g.large.search":"m6g.large.search","m6g.xlarge.search":"m6g.xlarge.search","m6g.2xlarge.search":"m6g.2xlarge.search","r6g.large.search":"r6g.large.search","r6g.xlarge.search":"r6g.xlarge.search","r6g.2xlarge.search":"r6g.2xlarge.search","r6g.4xlarge.search":"r6g.4xlarge.search","c6g.large.search":"c6g.large.search","c6g.xlarge.search":"c6g.xlarge.search","c6g.2xlarge.search":"c6g.2xlarge.search"};static EngineVersions={"OpenSearch_2.11":"OpenSearch_2.11","OpenSearch_2.9":"OpenSearch_2.9","OpenSearch_2.7":"OpenSearch_2.7","OpenSearch_1.3":"OpenSearch_1.3","Elasticsearch_7.10":"Elasticsearch_7.10"}}class Nt{static createDomainRedirectBucket(e){let{slug:n,environment:r,sourceDomain:i,targetDomain:s,protocol:a="https"}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"redirect"}),u=o(c),d=o(`${c}-policy`),m={Type:"AWS::S3::Bucket",Properties:{BucketName:i,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:s,Protocol:a}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Domain Redirect"}]}},p={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:v.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[v.Join("",[v.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:m,bucketPolicy:p,logicalId:u,policyLogicalId:d}}static createPathRedirectFunction(e){let{slug:n,environment:r,rules:i}=e,s=l({slug:n,environment:r,resourceType:"cf-redirect"}),a=o(s),c=Nt.generateRedirectFunctionCode(i);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:s,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${n} (${r})`,Runtime:"cloudfront-js-2.0"},FunctionCode:c}},logicalId:a,functionCode:c}}static generateRedirectFunctionCode(e){return`function handler(event) {
|
|
2281
|
+
| limit 50`,region:i,title:"Recent Errors and Warnings"}}),c+=6;return Gi.createDashboard({slug:n,environment:r,widgets:a})}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((n,r)=>({type:"metric",x:r%3*8,y:7+Math.floor(r/3)*6,width:8,height:6,properties:{title:`${n} Metrics`,region:e.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",n],["AWS/Lambda","Duration","FunctionName",n],["AWS/Lambda","Errors","FunctionName",n]],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:n,namespace:r,threshold:i,comparisonOperator:s="GreaterThanThreshold",evaluationPeriods:a=1,period:c=300,statistic:u="Average",treatMissingData:d="missing"}=e;return{MetricName:n,Namespace:r,Threshold:i,ComparisonOperator:s,EvaluationPeriods:a,Period:c,Statistic:u,TreatMissingData:d}},namespaces:{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",sqs:"AWS/SQS",sns:"AWS/SNS",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apiGateway:"AWS/ApiGateway",dynamodb:"AWS/DynamoDB",elasticache:"AWS/ElastiCache"},comparisonOperators:{greaterThan:"GreaterThanThreshold",greaterOrEqual:"GreaterThanOrEqualToThreshold",lessThan:"LessThanThreshold",lessOrEqual:"LessThanOrEqualToThreshold"},metrics:{ec2:{cpu:{metricName:"CPUUtilization",namespace:"AWS/EC2"},networkIn:{metricName:"NetworkIn",namespace:"AWS/EC2"},networkOut:{metricName:"NetworkOut",namespace:"AWS/EC2"},statusCheck:{metricName:"StatusCheckFailed",namespace:"AWS/EC2"}},ecs:{cpu:{metricName:"CPUUtilization",namespace:"AWS/ECS"},memory:{metricName:"MemoryUtilization",namespace:"AWS/ECS"}},lambda:{invocations:{metricName:"Invocations",namespace:"AWS/Lambda"},errors:{metricName:"Errors",namespace:"AWS/Lambda"},duration:{metricName:"Duration",namespace:"AWS/Lambda"},throttles:{metricName:"Throttles",namespace:"AWS/Lambda"},concurrentExecutions:{metricName:"ConcurrentExecutions",namespace:"AWS/Lambda"}},rds:{cpu:{metricName:"CPUUtilization",namespace:"AWS/RDS"},connections:{metricName:"DatabaseConnections",namespace:"AWS/RDS"},freeStorage:{metricName:"FreeStorageSpace",namespace:"AWS/RDS"},readLatency:{metricName:"ReadLatency",namespace:"AWS/RDS"},writeLatency:{metricName:"WriteLatency",namespace:"AWS/RDS"}},alb:{requestCount:{metricName:"RequestCount",namespace:"AWS/ApplicationELB"},responseTime:{metricName:"TargetResponseTime",namespace:"AWS/ApplicationELB"},httpCode4xx:{metricName:"HTTPCode_Target_4XX_Count",namespace:"AWS/ApplicationELB"},httpCode5xx:{metricName:"HTTPCode_Target_5XX_Count",namespace:"AWS/ApplicationELB"},healthyHosts:{metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB"}},sqs:{messagesVisible:{metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS"},messagesDelayed:{metricName:"ApproximateNumberOfMessagesDelayed",namespace:"AWS/SQS"},messageAge:{metricName:"ApproximateAgeOfOldestMessage",namespace:"AWS/SQS"}}},presets:{highCpu:(e=80)=>({metricName:"CPUUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(e=80)=>({metricName:"MemoryUtilization",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(e=10)=>({metricName:"Errors",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(e=5000)=>({metricName:"Duration",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(e=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(e=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:e,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(e=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:e,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class De{static createUserPool(e){let{slug:n,environment:r,userPoolName:i,aliasAttributes:s,autoVerifiedAttributes:a,passwordPolicy:c,mfaConfiguration:u,emailConfiguration:d,smsConfiguration:m,lambdaTriggers:p,userPoolAddOns:g,accountRecoverySetting:y}=e,f=i||l({slug:n,environment:r,resourceType:"user-pool"}),h=o(f),S={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:f,Policies:c?{PasswordPolicy:{MinimumLength:c.minimumLength,RequireLowercase:c.requireLowercase,RequireUppercase:c.requireUppercase,RequireNumbers:c.requireNumbers,RequireSymbols:c.requireSymbols,TemporaryPasswordValidityDays:c.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:u,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(s&&s.length>0)S.Properties.UsernameAttributes=s;if(a&&a.length>0)S.Properties.AutoVerifiedAttributes=a;if(d)S.Properties.EmailConfiguration={EmailSendingAccount:d.emailSendingAccount,From:d.from,ReplyToEmailAddress:d.replyToEmailAddress,SourceArn:d.sourceArn,ConfigurationSet:d.configurationSet};if(m)S.Properties.SmsConfiguration={ExternalId:m.externalId,SnsCallerArn:m.snsCallerArn};if(p)S.Properties.LambdaConfig={PreSignUp:p.preSignUp,PostConfirmation:p.postConfirmation,PreAuthentication:p.preAuthentication,PostAuthentication:p.postAuthentication,CustomMessage:p.customMessage,DefineAuthChallenge:p.defineAuthChallenge,CreateAuthChallenge:p.createAuthChallenge,VerifyAuthChallengeResponse:p.verifyAuthChallengeResponse,PreTokenGeneration:p.preTokenGeneration,UserMigration:p.userMigration};if(g)S.Properties.UserPoolAddOns={AdvancedSecurityMode:g.advancedSecurityMode};if(y)S.Properties.AccountRecoverySetting={RecoveryMechanisms:y.recoveryMechanisms};return{userPool:S,logicalId:h}}static createUserPoolClient(e,n){let{slug:r,environment:i,clientName:s,generateSecret:a=!1,refreshTokenValidity:c,accessTokenValidity:u,idTokenValidity:d,tokenValidityUnits:m,readAttributes:p,writeAttributes:g,explicitAuthFlows:y,preventUserExistenceErrors:f,enableTokenRevocation:h,callbackURLs:S,logoutURLs:A,allowedOAuthFlows:R,allowedOAuthScopes:P,allowedOAuthFlowsUserPoolClient:C,supportedIdentityProviders:E}=n,D=s||l({slug:r,environment:i,resourceType:"user-pool-client"}),x=o(D);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:D,UserPoolId:v.Ref(e),GenerateSecret:a,RefreshTokenValidity:c,AccessTokenValidity:u,IdTokenValidity:d,TokenValidityUnits:m,ReadAttributes:p,WriteAttributes:g,ExplicitAuthFlows:y,PreventUserExistenceErrors:f,EnableTokenRevocation:h,CallbackURLs:S,LogoutURLs:A,AllowedOAuthFlows:R,AllowedOAuthScopes:P,AllowedOAuthFlowsUserPoolClient:C,SupportedIdentityProviders:E}},logicalId:x}}static createUserPoolDomain(e,n){let{slug:r,environment:i,domain:s,customDomainConfig:a}=n,c=l({slug:r,environment:i,resourceType:"user-pool-domain"}),u=o(c);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:s,UserPoolId:v.Ref(e),CustomDomainConfig:a}},logicalId:u}}static createIdentityPool(e){let{slug:n,environment:r,identityPoolName:i,allowUnauthenticatedIdentities:s=!1,cognitoIdentityProviders:a,supportedLoginProviders:c,samlProviderARNs:u,openIdConnectProviderARNs:d}=e,m=i||l({slug:n,environment:r,resourceType:"identity-pool"}),p=o(m);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:m,AllowUnauthenticatedIdentities:s,CognitoIdentityProviders:a,SupportedLoginProviders:c,SamlProviderARNs:u,OpenIdConnectProviderARNs:d}},logicalId:p}}static createIdentityPoolRoleAttachment(e,n){let{slug:r,environment:i,authenticatedRole:s,unauthenticatedRole:a,roleMappings:c}=n,u=l({slug:r,environment:i,resourceType:"identity-pool-role-attachment"}),d=o(u),m={authenticated:s};if(a)m.unauthenticated=a;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:v.Ref(e),Roles:m,RoleMappings:c}},logicalId:d}}static createAuthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,s=l({slug:n,environment:r,resourceType:"cognito-authenticated-role"}),a=o(s);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":v.Ref(i)},"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:s},{Key:"Environment",Value:r}]}},logicalId:a}}static createUnauthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,s=l({slug:n,environment:r,resourceType:"cognito-unauthenticated-role"}),a=o(s);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":v.Ref(i)},"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:s},{Key:"Environment",Value:r}]}},logicalId:a}}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,n,r)=>{let{userPool:i,logicalId:s}=De.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:De.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:a,logicalId:c}=De.createUserPoolClient(s,{slug:e,environment:n,explicitAuthFlows:[...De.AuthFlows.standard],callbackURLs:[r],allowedOAuthFlows:["code"],allowedOAuthScopes:[...De.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:i,poolId:s,client:a,clientId:c}},mobileApp:(e,n)=>{let{userPool:r,logicalId:i}=De.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:De.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:s,logicalId:a}=De.createUserPoolClient(i,{slug:e,environment:n,explicitAuthFlows:[...De.AuthFlows.standard]}),{identityPool:c,logicalId:u}=De.createIdentityPool({slug:e,environment:n,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:v.Ref(a),ProviderName:v.GetAtt(i,"ProviderName")}]}),{role:d,logicalId:m}=De.createAuthenticatedRole({slug:e,environment:n,identityPoolLogicalId:u}),{attachment:p,logicalId:g}=De.createIdentityPoolRoleAttachment(u,{slug:e,environment:n,authenticatedRole:v.GetAtt(m,"Arn")});return{userPool:r,poolId:i,client:s,clientId:a,identityPool:c,identityPoolId:u,authRole:d,authRoleId:m,attachment:p,attachmentId:g}}}}import{createHash as ai}from"node:crypto";import{copyFileSync as oi,existsSync as Ct,readdirSync as ci,readFileSync as tt,statSync as li,writeFileSync as nt}from"node:fs";import{basename as ui,dirname as mn,extname as pn,join as je}from"node:path";class ke{static createApplication(e){let{slug:n,environment:r,applicationName:i,computePlatform:s}=e,a=i||l({slug:n,environment:r,resourceType:"deploy-app"}),c=o(a);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:a,ComputePlatform:s,Tags:[{Key:"Name",Value:a},{Key:"Environment",Value:r}]}},logicalId:c}}static createDeploymentGroup(e,n){let{slug:r,environment:i,deploymentGroupName:s,serviceRoleArn:a,autoScalingGroups:c,ec2TagFilters:u,deploymentConfigName:d,autoRollbackConfiguration:m,alarmConfiguration:p,loadBalancerInfo:g,blueGreenDeploymentConfiguration:y}=n,f=s||l({slug:r,environment:i,resourceType:"deploy-group"}),h=o(f);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:v.Ref(e),DeploymentGroupName:f,ServiceRoleArn:a,AutoScalingGroups:c,Ec2TagFilters:u?.map((A)=>({Key:A.key,Value:A.value,Type:A.type})),DeploymentConfigName:d,AutoRollbackConfiguration:m?{Enabled:m.enabled,Events:m.events}:void 0,AlarmConfiguration:p?{Enabled:p.enabled,Alarms:p.alarms?.map((A)=>({Name:A.name})),IgnorePollAlarmFailure:p.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:g?{TargetGroupInfoList:g.targetGroupInfoList?.map((A)=>({Name:A.name})),ElbInfoList:g.elbInfoList?.map((A)=>({Name:A.name}))}:void 0,BlueGreenDeploymentConfiguration:y?{TerminateBlueInstancesOnDeploymentSuccess:y.terminateBlueInstancesOnDeploymentSuccess?{Action:y.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:y.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:y.deploymentReadyOption?{ActionOnTimeout:y.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:y.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:y.greenFleetProvisioningOption?{Action:y.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:i}]}},logicalId:h}}static createDeploymentConfig(e){let{slug:n,environment:r,deploymentConfigName:i,minimumHealthyHosts:s,trafficRoutingConfig:a}=e,c=i||l({slug:n,environment:r,resourceType:"deploy-config"}),u=o(c);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:c,MinimumHealthyHosts:s?{Type:s.type,Value:s.value}:void 0,TrafficRoutingConfig:a?{Type:a.type,TimeBasedCanary:a.timeBasedCanary?{CanaryPercentage:a.timeBasedCanary.canaryPercentage,CanaryInterval:a.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:a.timeBasedLinear?{LinearPercentage:a.timeBasedLinear.linearPercentage,LinearInterval:a.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:u}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(e,n)=>({type:e,value:n})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(e,n)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:e,canaryInterval:n}}),linear:(e,n)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:e,linearInterval:n}})};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,n,r,i)=>{let{application:s,logicalId:a}=ke.createApplication({slug:e,environment:n,computePlatform:"Server"}),{deploymentGroup:c,logicalId:u}=ke.createDeploymentGroup(a,{slug:e,environment:n,serviceRoleArn:r,autoScalingGroups:i,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:ke.RollbackConfigs.onFailure()});return{application:s,appId:a,deploymentGroup:c,groupId:u}},lambdaCanaryDeployment:(e,n,r,i=10,s=5)=>{let{application:a,logicalId:c}=ke.createApplication({slug:e,environment:n,computePlatform:"Lambda"}),{deploymentConfig:u,logicalId:d}=ke.createDeploymentConfig({slug:e,environment:n,trafficRoutingConfig:ke.TrafficRouting.canary(i,s)}),{deploymentGroup:m,logicalId:p}=ke.createDeploymentGroup(c,{slug:e,environment:n,serviceRoleArn:r,deploymentConfigName:v.Ref(d),autoRollbackConfiguration:ke.RollbackConfigs.onAlarmOrFailure()});return{application:a,appId:c,deploymentConfig:u,configId:d,deploymentGroup:m,groupId:p}},ecsBlueGreenDeployment:(e,n,r,i)=>{let{application:s,logicalId:a}=ke.createApplication({slug:e,environment:n,computePlatform:"ECS"}),{deploymentGroup:c,logicalId:u}=ke.createDeploymentGroup(a,{slug:e,environment:n,serviceRoleArn:r,loadBalancerInfo:{targetGroupInfoList:[{name:i}]},blueGreenDeploymentConfiguration:ke.BlueGreenConfigs.standard(),autoRollbackConfiguration:ke.RollbackConfigs.onFailure()});return{application:s,appId:a,deploymentGroup:c,groupId:u}}};static Strategies={rolling:(e=25)=>({type:"rolling",batchPercentage:e}),blueGreen:()=>({type:"blue-green"}),canary:(e=10,n=5)=>({type:"canary",canaryPercentage:e,canaryInterval:n}),allAtOnce:()=>({type:"all-at-once"})}}class se{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,n="md5"){let r=tt(e);return ai(n).update(r).digest("hex")}static computeShortHash(e){return se.computeFileHash(e).slice(0,8)}static getContentType(e){let n=pn(e).toLowerCase();return se.ContentTypes[n]||"application/octet-stream"}static shouldHashFile(e,n){return![...se.NoHashPatterns,...n||[]].some((i)=>i.test(e))}static generateHashedFilename(e,n){let r=pn(e),i=ui(e,r),s=mn(e);if(s===".")return`${i}.${n}${r}`;return je(s,`${i}.${n}${r}`)}static collectFiles(e,n){let r=[],i=n||e;if(!Ct(e))return r;let s=ci(e,{withFileTypes:!0});for(let a of s){let c=je(e,a.name);if(a.isDirectory())r.push(...se.collectFiles(c,i));else if(a.isFile())r.push(c)}return r}static hashDirectory(e){let{sourceDir:n,outputDir:r,excludePatterns:i=[],hashAlgorithm:s="md5",copyUnhashed:a=!0}=e,c=se.collectFiles(n),u=[],d={};for(let p of c){let g=p.replace(n,"").replace(/^[/\\]/,""),y=se.shouldHashFile(g,i),f=li(p),h=y?se.computeFileHash(p,s).slice(0,8):"",S=y?se.generateHashedFilename(g,h):g,A={originalPath:g,hashedPath:S,hash:h,size:f.size,contentType:se.getContentType(p)};if(u.push(A),d[g]=S,r){let R=je(r,S),P=mn(R);if(!Ct(P)){let{mkdirSync:C}=ml("node:fs");C(P,{recursive:!0})}if(y||a)oi(p,R)}}let m={version:"1.0",timestamp:new Date().toISOString(),assets:u,hashMap:d};if(r){let p=je(r,"asset-manifest.json");nt(p,JSON.stringify(m,null,2))}return m}static getInvalidationPaths(e,n){let r=[];if(!e)return["/*"];let i=e.hashMap,s=n.hashMap;for(let[a,c]of Object.entries(s)){let u=i[a];if(!u||u!==c){if(r.push(`/${a}`),u&&u!==c)r.push(`/${u}`)}}for(let[a,c]of Object.entries(i))if(!s[a])r.push(`/${a}`),r.push(`/${c}`);if(r.length>100)return["/*"];return[...new Set(r)]}static updateHtmlReferences(e){let{htmlDir:n,manifest:r,basePath:i=""}=e,s=se.collectFiles(n).filter((a)=>a.endsWith(".html")||a.endsWith(".htm"));for(let a of s){let c=tt(a,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=[new RegExp(`(src|href)=["']${i}/?${se.escapeRegExp(u)}["']`,"g"),new RegExp(`url\\(["']?${i}/?${se.escapeRegExp(u)}["']?\\)`,"g")];for(let p of m)c=c.replace(p,(g)=>g.replace(u,d))}nt(a,c)}}static updateCssReferences(e){let{cssDir:n,manifest:r,basePath:i=""}=e,s=se.collectFiles(n).filter((a)=>a.endsWith(".css"));for(let a of s){let c=tt(a,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=new RegExp(`url\\(["']?${i}/?${se.escapeRegExp(u)}["']?\\)`,"g");c=c.replace(m,`url(${i}/${d})`)}nt(a,c)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:n,keyPrefix:r="",excludePatterns:i=[],cacheControl:s={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return se.hashDirectory({sourceDir:n,excludePatterns:i}).assets.map((c)=>{let u=c.hash!=="",d=c.contentType==="text/html",m=s.unhashed||"public, max-age=3600";if(d)m=s.html||"public, max-age=0, must-revalidate";else if(u)m=s.hashed||"public, max-age=31536000, immutable";return{localPath:je(n,c.originalPath),s3Key:r?`${r}/${c.hashedPath}`:c.hashedPath,contentType:c.contentType,cacheControl:m,hash:c.hash}})}static compareManifests(e,n){let r={added:[],removed:[],changed:[],unchanged:[]},i=new Set(Object.keys(e.hashMap)),s=new Set(Object.keys(n.hashMap));for(let a of s)if(!i.has(a))r.added.push(a);for(let a of i)if(!s.has(a))r.removed.push(a);for(let a of s)if(i.has(a))if(e.hashMap[a]!==n.hashMap[a])r.changed.push(a);else r.unchanged.push(a);return r}static loadManifest(e){if(!Ct(e))return null;try{let n=tt(e,"utf-8");return JSON.parse(n)}catch{return null}}static saveManifest(e,n){nt(n,JSON.stringify(e,null,2))}}class qi{static createSecret(e){let{slug:n,environment:r,secretName:i,description:s,secretString:a,kmsKeyId:c,tags:u}=e,d=i||l({slug:n,environment:r,resourceType:"secret"}),m=o(d),p={Type:"AWS::SecretsManager::Secret",Properties:{Name:d,Description:s,SecretString:a,Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},...u?Object.entries(u).map(([g,y])=>({Key:g,Value:y})):[]]}};if(c)p.Properties.KmsKeyId=c;return{secret:p,logicalId:m}}static createGeneratedSecret(e){let{slug:n,environment:r,secretName:i,description:s,excludeCharacters:a,excludeLowercase:c,excludeNumbers:u,excludePunctuation:d,excludeUppercase:m,passwordLength:p,requireEachIncludedType:g,kmsKeyId:y,tags:f}=e,h=i||l({slug:n,environment:r,resourceType:"secret"}),S=o(h),A={Type:"AWS::SecretsManager::Secret",Properties:{Name:h,Description:s,GenerateSecretString:{ExcludeCharacters:a,ExcludeLowercase:c,ExcludeNumbers:u,ExcludePunctuation:d,ExcludeUppercase:m,PasswordLength:p||32,RequireEachIncludedType:g!==!1},Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:r},...f?Object.entries(f).map(([R,P])=>({Key:R,Value:P})):[]]}};if(y)A.Properties.KmsKeyId=y;return{secret:A,logicalId:S}}static createDatabaseSecret(e){let{slug:n,environment:r,secretName:i,username:s,dbname:a,engine:c,host:u,port:d,kmsKeyId:m}=e,p=i||l({slug:n,environment:r,resourceType:"db-secret"}),g=o(p),y={username:s};if(a)y.dbname=a;if(c)y.engine=c;if(u)y.host=u;if(d)y.port=d;let f={Type:"AWS::SecretsManager::Secret",Properties:{Name:p,Description:`Database credentials for ${s}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(y),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:p},{Key:"Environment",Value:r},{Key:"Type",Value:"database"}]}};if(m)f.Properties.KmsKeyId=m;return{secret:f,logicalId:g}}static attachToDatabase(e){let{slug:n,environment:r,secretId:i,targetId:s,targetType:a}=e,c=l({slug:n,environment:r,resourceType:"secret-attachment"}),u=o(c);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:i,TargetId:s,TargetType:a}},logicalId:u}}static enableRotation(e){let{slug:n,environment:r,secretId:i,rotationLambdaArn:s,automaticallyAfterDays:a,rotationType:c,kmsKeyArn:u,vpcSecurityGroupIds:d,vpcSubnetIds:m}=e,p=l({slug:n,environment:r,resourceType:"secret-rotation"}),g=o(p),y={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:i,RotationRules:{AutomaticallyAfterDays:a||30}}};if(s)y.Properties.RotationLambdaARN=s;else if(c)y.Properties.HostedRotationLambda={RotationType:c,KmsKeyArn:u,VpcSecurityGroupIds:d,VpcSubnetIds:m};return{rotation:y,logicalId:g}}static SecretTypes={apiKey:(e,n,r)=>qi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-${r}-api-key`,description:`API key for ${r}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(e,n,r)=>qi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-${r}-oauth-secret`,description:`OAuth client secret for ${r}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(e,n)=>qi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,n)=>qi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-encryption-key`,description:"Data encryption key",passwordLength:64,excludeCharacters:"+/=",excludePunctuation:!0})};static RotationTypes={MySQLSingleUser:"MySQLSingleUser",MySQLMultiUser:"MySQLMultiUser",PostgreSQLSingleUser:"PostgreSQLSingleUser",PostgreSQLMultiUser:"PostgreSQLMultiUser",OracleSingleUser:"OracleSingleUser",OracleMultiUser:"OracleMultiUser",MariaDBSingleUser:"MariaDBSingleUser",MariaDBMultiUser:"MariaDBMultiUser",SQLServerSingleUser:"SQLServerSingleUser",SQLServerMultiUser:"SQLServerMultiUser",RedshiftSingleUser:"RedshiftSingleUser",RedshiftMultiUser:"RedshiftMultiUser",MongoDBSingleUser:"MongoDBSingleUser",MongoDBMultiUser:"MongoDBMultiUser"}}class X{static createParameter(e){let{slug:n,environment:r,parameterName:i,value:s,type:a="String",description:c,tier:u="Standard",tags:d}=e,m=i||l({slug:n,environment:r,resourceType:"parameter"}),p=o(m);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${n}/${r}/${m}`,Type:a,Value:s,Description:c,Tier:u,Tags:{Name:m,Environment:r,...d}}},logicalId:p}}static createString(e,n,r,i,s){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"String",description:s})}static createSecureString(e,n,r,i,s){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"SecureString",description:s})}static createStringList(e,n,r,i,s){return X.createParameter({slug:e,environment:n,parameterName:r,value:i.join(","),type:"StringList",description:s})}static Parameters={databaseUrl:(e,n,r)=>X.createSecureString(e,n,"database-url",r,"Database connection URL"),apiEndpoint:(e,n,r)=>X.createString(e,n,"api-endpoint",r,"API endpoint URL"),appVersion:(e,n,r)=>X.createString(e,n,"app-version",r,"Application version"),featureFlags:(e,n,r)=>X.createStringList(e,n,"feature-flags",r,"Enabled feature flags"),apiKey:(e,n,r,i)=>X.createSecureString(e,n,`${r}-api-key`,i,`API key for ${r}`),oauthCredentials:(e,n,r,i)=>{let s=X.createString(e,n,"oauth-client-id",r,"OAuth client ID"),a=X.createSecureString(e,n,"oauth-client-secret",i,"OAuth client secret");return{clientId:s,clientSecret:a}},smtpCredentials:(e,n,r,i,s,a)=>{let c=X.createString(e,n,"smtp-username",r,"SMTP username"),u=X.createSecureString(e,n,"smtp-password",i,"SMTP password"),d=X.createString(e,n,"smtp-host",s,"SMTP host"),m=X.createString(e,n,"smtp-port",a.toString(),"SMTP port");return{username:c,password:u,host:d,port:m}},redisUrl:(e,n,r)=>X.createSecureString(e,n,"redis-url",r,"Redis connection URL"),s3Bucket:(e,n,r)=>X.createString(e,n,"s3-bucket",r,"S3 bucket name"),cloudFrontDistribution:(e,n,r)=>X.createString(e,n,"cloudfront-distribution-id",r,"CloudFront distribution ID")}}class tr{static createDomain(e){let{slug:n,environment:r,domainName:i,engineVersion:s="OpenSearch_2.11",instanceType:a="t3.small.search",instanceCount:c=1,volumeSize:u=10,volumeType:d="gp3",dedicatedMaster:m=!1,dedicatedMasterType:p,dedicatedMasterCount:g=3,multiAz:y=!1,availabilityZoneCount:f=2,vpc:h,encryption:S,enforceHttps:A=!0,tlsSecurityPolicy:R="Policy-Min-TLS-1-2-2019-07",advancedSecurity:P,autoSnapshotHour:C=0,autoTune:E=!0,tags:D={}}=e,x=i||l({slug:n,environment:r,resourceType:"search"}),L=o(x);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:x,EngineVersion:s,ClusterConfig:{InstanceType:a,InstanceCount:c,DedicatedMasterEnabled:m,...m&&{DedicatedMasterType:p||a,DedicatedMasterCount:g},ZoneAwarenessEnabled:y,...y&&{ZoneAwarenessConfig:{AvailabilityZoneCount:f}}},EBSOptions:{EBSEnabled:!0,VolumeType:d,VolumeSize:u},DomainEndpointOptions:{EnforceHTTPS:A,TLSSecurityPolicy:R},SnapshotOptions:{AutomatedSnapshotStartHour:C},...h&&{VPCOptions:{SubnetIds:h.subnetIds,SecurityGroupIds:h.securityGroupIds}},...S&&{EncryptionAtRestOptions:{Enabled:S.atRest??!0,...S.kmsKeyId&&{KmsKeyId:S.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:S.nodeToNode??!0}},...P&&{AdvancedSecurityOptions:{Enabled:P.enabled,InternalUserDatabaseEnabled:P.internalUserDatabase??!0,...P.masterUserName&&P.masterUserPassword&&{MasterUserOptions:{MasterUserName:P.masterUserName,MasterUserPassword:P.masterUserPassword}},...P.masterUserArn&&{MasterUserOptions:{MasterUserARN:P.masterUserArn}}}},...E&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:x},{Key:"Environment",Value:r},...Object.entries(D).map(([O,F])=>({Key:O,Value:F}))]}},logicalId:L}}static createAccessPolicy(e,n){let{ipAddresses:r,iamPrincipalArns:i,allowAll:s,vpcEndpoint:a}=n;if(s)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};let c=[];if(i&&i.length>0)c.push({Effect:"Allow",Principal:{AWS:i},Action:"es:*",Resource:e});if(r&&r.length>0)c.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e,Condition:{IpAddress:{"aws:SourceIp":r}}});if(a)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:e}]};return{Version:"2012-10-17",Statement:c}}static DomainPresets={development:(e,n)=>tr.createDomain({slug:e,environment:n,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(e,n,r)=>tr.createDomain({slug:e,environment:n,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(e,n)=>tr.createDomain({slug:e,environment:n,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(e,n,r)=>tr.createDomain({slug:e,environment:n,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:r,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!1},autoTune:!0})};static InstanceTypes={"t3.small.search":"t3.small.search","t3.medium.search":"t3.medium.search","m6g.large.search":"m6g.large.search","m6g.xlarge.search":"m6g.xlarge.search","m6g.2xlarge.search":"m6g.2xlarge.search","r6g.large.search":"r6g.large.search","r6g.xlarge.search":"r6g.xlarge.search","r6g.2xlarge.search":"r6g.2xlarge.search","r6g.4xlarge.search":"r6g.4xlarge.search","c6g.large.search":"c6g.large.search","c6g.xlarge.search":"c6g.xlarge.search","c6g.2xlarge.search":"c6g.2xlarge.search"};static EngineVersions={"OpenSearch_2.11":"OpenSearch_2.11","OpenSearch_2.9":"OpenSearch_2.9","OpenSearch_2.7":"OpenSearch_2.7","OpenSearch_1.3":"OpenSearch_1.3","Elasticsearch_7.10":"Elasticsearch_7.10"}}class _t{static createDomainRedirectBucket(e){let{slug:n,environment:r,sourceDomain:i,targetDomain:s,protocol:a="https"}=e,c=l({slug:n,environment:r,resourceType:"s3",suffix:"redirect"}),u=o(c),d=o(`${c}-policy`),m={Type:"AWS::S3::Bucket",Properties:{BucketName:i,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:s,Protocol:a}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:r},{Key:"Purpose",Value:"Domain Redirect"}]}},p={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:v.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[v.Join("",[v.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:m,bucketPolicy:p,logicalId:u,policyLogicalId:d}}static createPathRedirectFunction(e){let{slug:n,environment:r,rules:i}=e,s=l({slug:n,environment:r,resourceType:"cf-redirect"}),a=o(s),c=_t.generateRedirectFunctionCode(i);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:s,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${n} (${r})`,Runtime:"cloudfront-js-2.0"},FunctionCode:c}},logicalId:a,functionCode:c}}static generateRedirectFunctionCode(e){return`function handler(event) {
|
|
2282
2282
|
const request = event.request;
|
|
2283
2283
|
const uri = request.uri;
|
|
2284
2284
|
const querystring = request.querystring;
|
|
@@ -2332,7 +2332,7 @@ ${e.map((r)=>{let i=r.preserveQueryString!==!1,s=r.statusCode||301;return` '${r
|
|
|
2332
2332
|
}
|
|
2333
2333
|
|
|
2334
2334
|
return request;
|
|
2335
|
-
}`}static CommonRedirects={wwwToApex:(e,n="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${e}`,targetDomain:e,protocol:n,preservePath:!0}),apexToWww:(e,n="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:e,targetDomain:`www.${e}`,protocol:n,preservePath:!0}),httpToHttps:(e="/")=>({source:e,target:e,statusCode:301}),addTrailingSlash:(e)=>e.map((n)=>({source:n.endsWith("/")?n.slice(0,-1):n,target:n.endsWith("/")?n:`${n}/`,statusCode:301})),removeTrailingSlash:(e)=>e.map((n)=>({source:n.endsWith("/")&&n!=="/"?n:`${n}/`,target:n.endsWith("/")&&n!=="/"?n.slice(0,-1):n,statusCode:301}))};static Patterns={flattenBlogUrls:(e)=>e.map(({oldPath:n,newPath:r})=>({source:n,target:r,statusCode:301,preserveQueryString:!0})),categoryRename:(e,n)=>[{source:`/${e}`,target:`/${n}`,statusCode:301},{source:`/${e}/`,target:`/${n}/`,statusCode:301}],productSlugChange:(e)=>e.map(({oldSlug:n,newSlug:r})=>({source:`/products/${n}`,target:`/products/${r}`,statusCode:301})),apiVersionRedirect:(e,n,r)=>r.map((i)=>({source:`/api/${e}/${i}`,target:`/api/${n}/${i}`,statusCode:307,preserveQueryString:!0})),gonePages:(e)=>e.map((n)=>({source:n,target:"/410",statusCode:301}))};static createRedirectSetup(e){let{slug:n,environment:r,domainRedirects:i=[],pathRedirects:s=[]}=e,a={},c=[];for(let d of i){let{bucket:m,bucketPolicy:p,logicalId:g,policyLogicalId:y}=Nt.createDomainRedirectBucket({...d,slug:n,environment:r});a[g]=m,a[y]=p,c.push(g)}let u=null;if(s.length>0){let{function:d,logicalId:m}=Nt.createPathRedirectFunction({slug:n,environment:r,rules:s});a[m]=d,u=m}return{resources:a,outputs:{domainRedirectBuckets:c,pathRedirectFunctionLogicalId:u}}}static fromMapping(e,n){return Object.entries(e).map(([r,i])=>({source:r,target:i,statusCode:n?.statusCode||301,preserveQueryString:n?.preserveQueryString??!0}))}static validateRules(e){let n=[],r=[],i=new Set;for(let s of e){if(i.has(s.source))n.push(`Duplicate source path: ${s.source}`);if(i.add(s.source),s.source===s.target)n.push(`Redirect loop detected: ${s.source} -> ${s.target}`);if(!s.target.startsWith("/")&&!s.target.startsWith("http"))r.push(`Target URL should start with / or http: ${s.target}`);if(!s.source||s.source.trim()==="")n.push("Source path cannot be empty");if(!s.target||s.target.trim()==="")n.push("Target path cannot be empty")}for(let s of e){let a=e.find((c)=>c.source===s.target);if(a)r.push(`Potential redirect chain: ${s.source} -> ${s.target} -> ${a.target}`)}return{valid:n.length===0,errors:n,warnings:r}}}class ke{static generate(e){let n={},{slug:r,environment:i,region:s="us-east-1"}=e,a=ke.createLambdaExecutionRole(r,i);if(Object.assign(n,a.resources),e.email?.enabled){let c=ke.generateEmailResources(e,a.roleArn);Object.assign(n,c)}if(e.phone?.enabled){let c=ke.generatePhoneResources(e,a.roleArn);Object.assign(n,c)}if(e.sms?.enabled){let c=ke.generateSmsResources(e,a.roleArn);Object.assign(n,c)}return n}static createLambdaExecutionRole(e,n){let r=`${e}-${n}-communication-role`,i=o(r);return{resources:{[i]:{Type:"AWS::IAM::Role",Properties:{RoleName:r,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"CommunicationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish","sns:Subscribe"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchWriteItem","dynamodb:BatchGetItem"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"},{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetEndpoint","mobiletargeting:UpdateEndpoint"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["bedrock:InvokeModel"],Resource:"*"},{Effect:"Allow",Action:["es:ESHttpGet","es:ESHttpPost","es:ESHttpPut","es:ESHttpDelete"],Resource:"*"}]}}]}}},roleArn:v.GetAtt(i,"Arn"),roleName:r}}static generateEmailResources(e,n){let{slug:r,environment:i,email:s}=e;if(!s)return{};let a={},c=`${r}-${i}`,u=`${c}-email-storage`,d=o(u);a[d]={Type:"AWS::S3::Bucket",Properties:{BucketName:u,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:s.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:s.server.storage.archiveAfterDays}]:[],ExpirationInDays:s.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let m=o(`${c}-ses-identity`);if(a[m]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:s.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},s.notifications?.bounces||s.notifications?.complaints){let p=o(`${c}-bounce-topic`);a[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-bounces`}};let g=o(`${c}-complaint-topic`);a[g]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-complaints`}}}if(s.server?.enabled){let p=o(`${c}-inbound-email`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:60,MemorySize:256,Code:{ZipFile:ke.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:u,DOMAIN:s.domain}}}};let g=o(`${c}-outbound-email`);a[g]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:ke.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:u,DOMAIN:s.domain}}}}}if(s.advanced?.analytics){let p=o(`${c}-email-analytics`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.scheduling){let p=o(`${c}-email-scheduler`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:300,MemorySize:256,Code:{ZipFile:ke.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:u}}}};let g=o(`${c}-email-scheduler-rule`);a[g]={Type:"AWS::Events::Rule",Properties:{Name:`${c}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:v.GetAtt(p,"Arn")}]}}}if(s.advanced?.threading){let p=o(`${c}-email-threading`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:60,MemorySize:256,Code:{ZipFile:ke.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:u}}}}}if(s.advanced?.rules){let p=o(`${c}-email-rules`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-email-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"mailbox",AttributeType:"S"},{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"mailbox",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}]}}}if(s.advanced?.sharedMailboxes){let p=o(`${c}-shared-mailboxes`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-shared-mailboxes`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"},{AttributeName:"type",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"type-index",KeySchema:[{AttributeName:"type",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}}]}}}if(s.advanced?.search){let p=o(`${c}-email-search`);a[p]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${c}-email-search`.toLowerCase().replace(/[^a-z0-9-]/g,"-").substring(0,28),EngineVersion:"OpenSearch_2.11",ClusterConfig:{InstanceType:"t3.small.search",InstanceCount:1},EBSOptions:{EBSEnabled:!0,VolumeType:"gp3",VolumeSize:10},NodeToNodeEncryptionOptions:{Enabled:!0},EncryptionAtRestOptions:{Enabled:!0},DomainEndpointOptions:{EnforceHTTPS:!0}}}}return a}static generatePhoneResources(e,n){let{slug:r,environment:i,phone:s}=e;if(!s)return{};let a={},c=`${r}-${i}`,u=o(`${c}-call-log`);if(a[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},s.voicemail?.enabled){let p=o(`${c}-voicemail`);a[p]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let d=o(`${c}-phone-notifications`);a[d]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-phone-notifications`}};let m=o(`${c}-incoming-call`);if(a[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:ke.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${c}-call-log`,NOTIFICATION_TOPIC_ARN:v.Ref(d)}}}},s.voicemail?.enabled){let p=o(`${c}-voicemail-handler`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:s.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:ke.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${c}-voicemail`,TRANSCRIPTION_ENABLED:String(s.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:v.Ref(d)}}}}}if(s.advanced?.recording){let p=o(`${c}-call-recordings`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.callbacks){let p=o(`${c}-callbacks`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.analytics){let p=o(`${c}-call-metrics`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return a}static generateSmsResources(e,n){let{slug:r,environment:i,sms:s}=e;if(!s)return{};let a={},c=`${r}-${i}`,u=o(`${c}-pinpoint-app`);a[u]={Type:"AWS::Pinpoint::App",Properties:{Name:`${c}-sms`}};let d=o(`${c}-sms-channel`);a[d]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:v.Ref(u),Enabled:!0,SenderId:s.senderId}};let m=o(`${c}-sms-log`);if(a[m]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},s.optOut?.enabled){let f=o(`${c}-sms-optout`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let p=o(`${c}-sms-notifications`);a[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-sms-notifications`}};let g=o(`${c}-send-sms`);a[g]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:ke.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:v.Ref(u),MESSAGE_LOG_TABLE:`${c}-sms-log`,OPT_OUT_TABLE:s.optOut?.enabled?`${c}-sms-optout`:"",MESSAGE_TYPE:s.messageType||"TRANSACTIONAL"}}}};let y=o(`${c}-receive-sms`);if(a[y]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:ke.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${c}-sms-log`,OPT_OUT_TABLE:s.optOut?.enabled?`${c}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:v.Ref(p)}}}},s.advanced?.campaigns){let f=o(`${c}-sms-campaigns`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(s.advanced?.analytics){let f=o(`${c}-sms-analytics`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.linkTracking){let f=o(`${c}-short-links`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.chatbot){let f=o(`${c}-chatbot-sessions`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let h=o(`${c}-chatbot-rules`);a[h]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(s.advanced?.abTesting){let f=o(`${c}-ab-tests`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(s.advanced?.mms){let f=o(`${c}-mms-media`);a[f]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return a}static InboundEmailCode=`
|
|
2335
|
+
}`}static CommonRedirects={wwwToApex:(e,n="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${e}`,targetDomain:e,protocol:n,preservePath:!0}),apexToWww:(e,n="https")=>({slug:e.replace(/\./g,"-"),environment:"production",sourceDomain:e,targetDomain:`www.${e}`,protocol:n,preservePath:!0}),httpToHttps:(e="/")=>({source:e,target:e,statusCode:301}),addTrailingSlash:(e)=>e.map((n)=>({source:n.endsWith("/")?n.slice(0,-1):n,target:n.endsWith("/")?n:`${n}/`,statusCode:301})),removeTrailingSlash:(e)=>e.map((n)=>({source:n.endsWith("/")&&n!=="/"?n:`${n}/`,target:n.endsWith("/")&&n!=="/"?n.slice(0,-1):n,statusCode:301}))};static Patterns={flattenBlogUrls:(e)=>e.map(({oldPath:n,newPath:r})=>({source:n,target:r,statusCode:301,preserveQueryString:!0})),categoryRename:(e,n)=>[{source:`/${e}`,target:`/${n}`,statusCode:301},{source:`/${e}/`,target:`/${n}/`,statusCode:301}],productSlugChange:(e)=>e.map(({oldSlug:n,newSlug:r})=>({source:`/products/${n}`,target:`/products/${r}`,statusCode:301})),apiVersionRedirect:(e,n,r)=>r.map((i)=>({source:`/api/${e}/${i}`,target:`/api/${n}/${i}`,statusCode:307,preserveQueryString:!0})),gonePages:(e)=>e.map((n)=>({source:n,target:"/410",statusCode:301}))};static createRedirectSetup(e){let{slug:n,environment:r,domainRedirects:i=[],pathRedirects:s=[]}=e,a={},c=[];for(let d of i){let{bucket:m,bucketPolicy:p,logicalId:g,policyLogicalId:y}=_t.createDomainRedirectBucket({...d,slug:n,environment:r});a[g]=m,a[y]=p,c.push(g)}let u=null;if(s.length>0){let{function:d,logicalId:m}=_t.createPathRedirectFunction({slug:n,environment:r,rules:s});a[m]=d,u=m}return{resources:a,outputs:{domainRedirectBuckets:c,pathRedirectFunctionLogicalId:u}}}static fromMapping(e,n){return Object.entries(e).map(([r,i])=>({source:r,target:i,statusCode:n?.statusCode||301,preserveQueryString:n?.preserveQueryString??!0}))}static validateRules(e){let n=[],r=[],i=new Set;for(let s of e){if(i.has(s.source))n.push(`Duplicate source path: ${s.source}`);if(i.add(s.source),s.source===s.target)n.push(`Redirect loop detected: ${s.source} -> ${s.target}`);if(!s.target.startsWith("/")&&!s.target.startsWith("http"))r.push(`Target URL should start with / or http: ${s.target}`);if(!s.source||s.source.trim()==="")n.push("Source path cannot be empty");if(!s.target||s.target.trim()==="")n.push("Target path cannot be empty")}for(let s of e){let a=e.find((c)=>c.source===s.target);if(a)r.push(`Potential redirect chain: ${s.source} -> ${s.target} -> ${a.target}`)}return{valid:n.length===0,errors:n,warnings:r}}}class Ne{static generate(e){let n={},{slug:r,environment:i,region:s="us-east-1"}=e,a=Ne.createLambdaExecutionRole(r,i);if(Object.assign(n,a.resources),e.email?.enabled){let c=Ne.generateEmailResources(e,a.roleArn);Object.assign(n,c)}if(e.phone?.enabled){let c=Ne.generatePhoneResources(e,a.roleArn);Object.assign(n,c)}if(e.sms?.enabled){let c=Ne.generateSmsResources(e,a.roleArn);Object.assign(n,c)}return n}static createLambdaExecutionRole(e,n){let r=`${e}-${n}-communication-role`,i=o(r);return{resources:{[i]:{Type:"AWS::IAM::Role",Properties:{RoleName:r,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"CommunicationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish","sns:Subscribe"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchWriteItem","dynamodb:BatchGetItem"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"},{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetEndpoint","mobiletargeting:UpdateEndpoint"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["bedrock:InvokeModel"],Resource:"*"},{Effect:"Allow",Action:["es:ESHttpGet","es:ESHttpPost","es:ESHttpPut","es:ESHttpDelete"],Resource:"*"}]}}]}}},roleArn:v.GetAtt(i,"Arn"),roleName:r}}static generateEmailResources(e,n){let{slug:r,environment:i,email:s}=e;if(!s)return{};let a={},c=`${r}-${i}`,u=`${c}-email-storage`,d=o(u);a[d]={Type:"AWS::S3::Bucket",Properties:{BucketName:u,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:s.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:s.server.storage.archiveAfterDays}]:[],ExpirationInDays:s.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let m=o(`${c}-ses-identity`);if(a[m]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:s.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},s.notifications?.bounces||s.notifications?.complaints){let p=o(`${c}-bounce-topic`);a[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-bounces`}};let g=o(`${c}-complaint-topic`);a[g]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-email-complaints`}}}if(s.server?.enabled){let p=o(`${c}-inbound-email`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:60,MemorySize:256,Code:{ZipFile:Ne.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:u,DOMAIN:s.domain}}}};let g=o(`${c}-outbound-email`);a[g]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:Ne.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:u,DOMAIN:s.domain}}}}}if(s.advanced?.analytics){let p=o(`${c}-email-analytics`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.scheduling){let p=o(`${c}-email-scheduler`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:300,MemorySize:256,Code:{ZipFile:Ne.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:u}}}};let g=o(`${c}-email-scheduler-rule`);a[g]={Type:"AWS::Events::Rule",Properties:{Name:`${c}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:v.GetAtt(p,"Arn")}]}}}if(s.advanced?.threading){let p=o(`${c}-email-threading`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:60,MemorySize:256,Code:{ZipFile:Ne.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:u}}}}}if(s.advanced?.rules){let p=o(`${c}-email-rules`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-email-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"mailbox",AttributeType:"S"},{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"mailbox",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}]}}}if(s.advanced?.sharedMailboxes){let p=o(`${c}-shared-mailboxes`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-shared-mailboxes`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"},{AttributeName:"type",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"type-index",KeySchema:[{AttributeName:"type",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}}]}}}if(s.advanced?.search){let p=o(`${c}-email-search`);a[p]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${c}-email-search`.toLowerCase().replace(/[^a-z0-9-]/g,"-").substring(0,28),EngineVersion:"OpenSearch_2.11",ClusterConfig:{InstanceType:"t3.small.search",InstanceCount:1},EBSOptions:{EBSEnabled:!0,VolumeType:"gp3",VolumeSize:10},NodeToNodeEncryptionOptions:{Enabled:!0},EncryptionAtRestOptions:{Enabled:!0},DomainEndpointOptions:{EnforceHTTPS:!0}}}}return a}static generatePhoneResources(e,n){let{slug:r,environment:i,phone:s}=e;if(!s)return{};let a={},c=`${r}-${i}`,u=o(`${c}-call-log`);if(a[u]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},s.voicemail?.enabled){let p=o(`${c}-voicemail`);a[p]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let d=o(`${c}-phone-notifications`);a[d]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-phone-notifications`}};let m=o(`${c}-incoming-call`);if(a[m]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:Ne.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${c}-call-log`,NOTIFICATION_TOPIC_ARN:v.Ref(d)}}}},s.voicemail?.enabled){let p=o(`${c}-voicemail-handler`);a[p]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:s.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:Ne.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${c}-voicemail`,TRANSCRIPTION_ENABLED:String(s.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:v.Ref(d)}}}}}if(s.advanced?.recording){let p=o(`${c}-call-recordings`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.callbacks){let p=o(`${c}-callbacks`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.analytics){let p=o(`${c}-call-metrics`);a[p]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return a}static generateSmsResources(e,n){let{slug:r,environment:i,sms:s}=e;if(!s)return{};let a={},c=`${r}-${i}`,u=o(`${c}-pinpoint-app`);a[u]={Type:"AWS::Pinpoint::App",Properties:{Name:`${c}-sms`}};let d=o(`${c}-sms-channel`);a[d]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:v.Ref(u),Enabled:!0,SenderId:s.senderId}};let m=o(`${c}-sms-log`);if(a[m]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},s.optOut?.enabled){let f=o(`${c}-sms-optout`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let p=o(`${c}-sms-notifications`);a[p]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${c}-sms-notifications`}};let g=o(`${c}-send-sms`);a[g]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:Ne.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:v.Ref(u),MESSAGE_LOG_TABLE:`${c}-sms-log`,OPT_OUT_TABLE:s.optOut?.enabled?`${c}-sms-optout`:"",MESSAGE_TYPE:s.messageType||"TRANSACTIONAL"}}}};let y=o(`${c}-receive-sms`);if(a[y]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${c}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n,Timeout:30,MemorySize:256,Code:{ZipFile:Ne.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${c}-sms-log`,OPT_OUT_TABLE:s.optOut?.enabled?`${c}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:v.Ref(p)}}}},s.advanced?.campaigns){let f=o(`${c}-sms-campaigns`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(s.advanced?.analytics){let f=o(`${c}-sms-analytics`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.linkTracking){let f=o(`${c}-short-links`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(s.advanced?.chatbot){let f=o(`${c}-chatbot-sessions`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let h=o(`${c}-chatbot-rules`);a[h]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(s.advanced?.abTesting){let f=o(`${c}-ab-tests`);a[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(s.advanced?.mms){let f=o(`${c}-mms-media`);a[f]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${c}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return a}static InboundEmailCode=`
|
|
2336
2336
|
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
2337
2337
|
const s3 = new S3Client({});
|
|
2338
2338
|
exports.handler = async (event) => {
|
|
@@ -2430,7 +2430,7 @@ exports.handler = async (event) => {
|
|
|
2430
2430
|
console.log('Receive SMS:', JSON.stringify(event, null, 2));
|
|
2431
2431
|
// Process inbound SMS, handle opt-out keywords
|
|
2432
2432
|
return { statusCode: 200 };
|
|
2433
|
-
};`}var t={ref:(e)=>({Ref:e}),getAtt:(e,n)=>({"Fn::GetAtt":[e,n]}),join:(e,n)=>({"Fn::Join":[e,n]}),sub:(e,n)=>n?{"Fn::Sub":[e,n]}:{"Fn::Sub":e},select:(e,n)=>({"Fn::Select":[e,n]}),split:(e,n)=>({"Fn::Split":[e,n]}),getAZs:(e="")=>({"Fn::GetAZs":e}),importValue:(e)=>({"Fn::ImportValue":e}),findInMap:(e,n,r)=>({"Fn::FindInMap":[e,n,r]}),base64:(e)=>({"Fn::Base64":e}),cidr:(e,n,r)=>({"Fn::Cidr":[e,n,r]}),equals:(e,n)=>({"Fn::Equals":[e,n]}),if:(e,n,r)=>({"Fn::If":[e,n,r]}),not:(e)=>({"Fn::Not":[e]}),and:(...e)=>({"Fn::And":e}),or:(...e)=>({"Fn::Or":e})},In={s3Bucket:(e)=>t.sub(`arn:aws:s3:::${e}`),s3Object:(e,n="*")=>t.sub(`arn:aws:s3:::${e}/${n}`),lambda:(e,n,r)=>t.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${e}`,n&&r?{"AWS::Region":n,"AWS::AccountId":r}:void 0),dynamodb:(e)=>t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${e}`),sqs:(e)=>t.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${e}`),sns:(e)=>t.sub(`arn:aws:sns:\${AWS::Region}:\${AWS::AccountId}:${e}`),kinesis:(e)=>t.sub(`arn:aws:kinesis:\${AWS::Region}:\${AWS::AccountId}:stream/${e}`),iam:(e,n)=>t.sub(`arn:aws:iam::\${AWS::AccountId}:${e}/${n}`),secretsManager:(e)=>t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${e}`),cloudwatch:(e)=>t.sub(`arn:aws:logs:\${AWS::Region}:\${AWS::AccountId}:log-group:${e}`)},_m={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 un(e,n){if(n.type==="http")Kr(e,n);else if(n.type==="rest")qr(e,n);else if(n.type==="websocket")Qr(e,n)}function Kr(e,n){let r={Name:t.sub("${AWS::StackName}-http-api"),ProtocolType:"HTTP"};if(n.cors)r.CorsConfiguration={AllowOrigins:n.cors.allowOrigins,AllowMethods:n.cors.allowMethods,AllowHeaders:n.cors.allowHeaders||["*"],MaxAge:n.cors.maxAge||300};if(e.addResource("HttpApi","AWS::ApiGatewayV2::Api",r),e.addResource("HttpApiStage","AWS::ApiGatewayV2::Stage",{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0,DefaultRouteSettings:n.throttling?{ThrottlingBurstLimit:n.throttling.burstLimit,ThrottlingRateLimit:n.throttling.rateLimit}:void 0,AccessLogSettings:{DestinationArn:t.getAtt("ApiLogGroup","Arn"),Format:"$context.requestId $context.error.message $context.error.messageString"}},{dependsOn:["HttpApi","ApiLogGroup"]}),e.addResource("ApiLogGroup","AWS::Logs::LogGroup",{LogGroupName:t.sub("/aws/apigateway/${AWS::StackName}-http-api"),RetentionInDays:14}),n.authorizer)Jr(e,"HttpApi",n.authorizer);if(n.customDomain)St(e,"HttpApi",n.customDomain,"HTTP");e.addOutputs({HttpApiId:{Description:"HTTP API ID",Value:t.ref("HttpApi"),Export:{Name:t.sub("${AWS::StackName}-http-api-id")}},HttpApiEndpoint:{Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint"),Export:{Name:t.sub("${AWS::StackName}-http-api-endpoint")}}})}function qr(e,n){e.addResource("RestApi","AWS::ApiGateway::RestApi",{Name:t.sub("${AWS::StackName}-rest-api"),Description:t.sub("REST API for ${AWS::StackName}"),EndpointConfiguration:{Types:["REGIONAL"]}}),e.addResource("ApiGatewayAccount","AWS::ApiGateway::Account",{CloudWatchRoleArn:t.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:t.ref("RestApi"),Description:"Initial deployment"},{dependsOn:"RestApi"});let r={RestApiId:t.ref("RestApi"),DeploymentId:t.ref("RestApiDeployment"),StageName:"prod",Description:"Production stage",MethodSettings:[{ResourcePath:"/*",HttpMethod:"*",LoggingLevel:"INFO",DataTraceEnabled:!0,MetricsEnabled:!0}]};if(n.throttling)r.MethodSettings[0].ThrottlingBurstLimit=n.throttling.burstLimit,r.MethodSettings[0].ThrottlingRateLimit=n.throttling.rateLimit;if(e.addResource("RestApiStage","AWS::ApiGateway::Stage",r,{dependsOn:["RestApi","RestApiDeployment"]}),n.customDomain)St(e,"RestApi",n.customDomain,"REST");e.addOutputs({RestApiId:{Description:"REST API ID",Value:t.ref("RestApi"),Export:{Name:t.sub("${AWS::StackName}-rest-api-id")}},RestApiEndpoint:{Description:"REST API endpoint",Value:t.sub("https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/prod"),Export:{Name:t.sub("${AWS::StackName}-rest-api-endpoint")}}})}function Qr(e,n){if(e.addResource("WebSocketApi","AWS::ApiGatewayV2::Api",{Name:t.sub("${AWS::StackName}-websocket-api"),ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action"}),n.routes){if(n.routes.connect)tt(e,"$connect",n.routes.connect.functionName);if(n.routes.disconnect)tt(e,"$disconnect",n.routes.disconnect.functionName);if(n.routes.default)tt(e,"$default",n.routes.default.functionName);if(n.routes.custom)n.routes.custom.forEach((r)=>{tt(e,r.routeKey,r.functionName)})}if(e.addResource("WebSocketApiStage","AWS::ApiGatewayV2::Stage",{ApiId:t.ref("WebSocketApi"),StageName:"prod",AutoDeploy:!0,DefaultRouteSettings:n.throttling?{ThrottlingBurstLimit:n.throttling.burstLimit,ThrottlingRateLimit:n.throttling.rateLimit}:void 0},{dependsOn:"WebSocketApi"}),n.customDomain)St(e,"WebSocketApi",n.customDomain,"WEBSOCKET");e.addOutputs({WebSocketApiId:{Description:"WebSocket API ID",Value:t.ref("WebSocketApi"),Export:{Name:t.sub("${AWS::StackName}-websocket-api-id")}},WebSocketApiEndpoint:{Description:"WebSocket API endpoint",Value:t.getAtt("WebSocketApi","ApiEndpoint"),Export:{Name:t.sub("${AWS::StackName}-websocket-api-endpoint")}}})}function tt(e,n,r){let i=e.toLogicalId(`websocket-route-${n}`),s=e.toLogicalId(`websocket-integration-${n}`),a=e.toLogicalId(`${r}-function`);e.addResource(s,"AWS::ApiGatewayV2::Integration",{ApiId:t.ref("WebSocketApi"),IntegrationType:"AWS_PROXY",IntegrationUri:t.sub(`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${a}.Arn}/invocations`)},{dependsOn:["WebSocketApi",a]}),e.addResource(i,"AWS::ApiGatewayV2::Route",{ApiId:t.ref("WebSocketApi"),RouteKey:n,Target:t.join("/",["integrations",t.ref(s)])},{dependsOn:["WebSocketApi",s]}),e.addResource(`${i}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(a),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*")},{dependsOn:[a,"WebSocketApi"]})}function St(e,n,r,i){let s={DomainName:r.domain};if(i==="REST")s.CertificateArn=r.certificateArn,s.EndpointConfiguration={Types:["REGIONAL"]},e.addResource("ApiCustomDomain","AWS::ApiGateway::DomainName",s),e.addResource("ApiBasePathMapping","AWS::ApiGateway::BasePathMapping",{DomainName:t.ref("ApiCustomDomain"),RestApiId:t.ref(n),Stage:t.ref("RestApiStage")},{dependsOn:["ApiCustomDomain",n,"RestApiStage"]});else s.DomainNameConfigurations=[{CertificateArn:r.certificateArn,EndpointType:"REGIONAL"}],e.addResource("ApiCustomDomain","AWS::ApiGatewayV2::DomainName",s),e.addResource("ApiMapping","AWS::ApiGatewayV2::ApiMapping",{ApiId:t.ref(n),DomainName:t.ref("ApiCustomDomain"),Stage:i==="HTTP"?t.ref("HttpApiStage"):t.ref("WebSocketApiStage")},{dependsOn:["ApiCustomDomain",n]});if(r.dnsProvider!=="external")e.addResource("ApiDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:t.sub(`${Yr(r.domain)}.`),Name:r.domain,Type:"A",AliasTarget:{HostedZoneId:t.getAtt("ApiCustomDomain","RegionalHostedZoneId"),DNSName:t.getAtt("ApiCustomDomain","RegionalDomainName"),EvaluateTargetHealth:!1}},{dependsOn:"ApiCustomDomain"});e.addOutputs({ApiCustomDomainName:{Description:"Configured API custom domain",Value:r.domain},ApiCustomDomainTarget:{Description:"DNS target for Route53 or an external DNS provider",Value:t.getAtt("ApiCustomDomain","RegionalDomainName")},ApiCustomDomainHostedZoneId:{Description:"Regional API Gateway hosted zone ID",Value:t.getAtt("ApiCustomDomain","RegionalHostedZoneId")}})}function Jr(e,n,r){if(!r)return;if(r.type==="jwt")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:t.ref(n),AuthorizerType:"JWT",IdentitySource:[r.identitySource||"$request.header.Authorization"],JwtConfiguration:{Issuer:r.issuer,Audience:r.audience},Name:"JWTAuthorizer"},{dependsOn:n});else if(r.type==="lambda")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:t.ref(n),AuthorizerType:"REQUEST",AuthorizerUri:r.authorizerUri,IdentitySource:[r.identitySource||"$request.header.Authorization"],Name:"LambdaAuthorizer"},{dependsOn:n})}function Yr(e){let n=e.split(".");if(n.length>=2)return n.slice(-2).join(".");return e}function dn(e,n){if(n.redis)Zr(e,n.redis);if(n.memcached)Xr(e,n.memcached);if(n.elasticache)ei(e,n.elasticache)}function Zr(e,n){if(!n)return;if(e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache Redis cluster",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Redis",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:n.port||6379,ToPort:n.port||6379,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]}),n.parameterGroup&&Object.keys(n.parameterGroup).length>0)e.addResource("CacheParameterGroup","AWS::ElastiCache::ParameterGroup",{Description:"Parameter group for Redis",CacheParameterGroupFamily:`redis${n.engineVersion.split(".")[0]}`,Properties:n.parameterGroup});if(n.numCacheNodes>1||n.automaticFailoverEnabled)e.addResource("RedisReplicationGroup","AWS::ElastiCache::ReplicationGroup",{ReplicationGroupDescription:"Redis replication group",ReplicationGroupId:t.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:n.engineVersion,CacheNodeType:n.nodeType,NumCacheClusters:n.numCacheNodes,AutomaticFailoverEnabled:n.automaticFailoverEnabled||!1,MultiAZEnabled:n.automaticFailoverEnabled||!1,Port:n.port||6379,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.ref("CacheSecurityGroup")],CacheParameterGroupName:n.parameterGroup?t.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:n.snapshotRetentionLimit||5,SnapshotWindow:n.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",AtRestEncryptionEnabled:!0,TransitEncryptionEnabled:!0,Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-redis")}]},{dependsOn:n.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis primary endpoint",Value:t.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address"),Export:{Name:t.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:t.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port"),Export:{Name:t.sub("${AWS::StackName}-redis-port")}}});else e.addResource("RedisCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:t.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:n.engineVersion,CacheNodeType:n.nodeType,NumCacheNodes:1,Port:n.port||6379,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[t.ref("CacheSecurityGroup")],CacheParameterGroupName:n.parameterGroup?t.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:n.snapshotRetentionLimit||5,SnapshotWindow:n.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-redis")}]},{dependsOn:n.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis endpoint",Value:t.getAtt("RedisCacheCluster","RedisEndpoint.Address"),Export:{Name:t.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:t.getAtt("RedisCacheCluster","RedisEndpoint.Port"),Export:{Name:t.sub("${AWS::StackName}-redis-port")}}})}function Xr(e,n){if(!n)return;if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Memcached",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:n.port||11211,ToPort:n.port||11211,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("MemcachedCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:t.sub("${AWS::StackName}-memcached"),Engine:"memcached",EngineVersion:n.engineVersion,CacheNodeType:n.nodeType,NumCacheNodes:n.numCacheNodes,Port:n.port||11211,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[t.ref("CacheSecurityGroup")],PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-memcached")}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]}),e.addOutputs({MemcachedEndpoint:{Description:"Memcached configuration endpoint",Value:t.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Address"),Export:{Name:t.sub("${AWS::StackName}-memcached-endpoint")}},MemcachedPort:{Description:"Memcached port",Value:t.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Port"),Export:{Name:t.sub("${AWS::StackName}-memcached-port")}}})}function ei(e,n){if(!n)return;let r=n.engine==="redis";if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:r?6379:11211,ToPort:r?6379:11211,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("CacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:t.sub(`\${AWS::StackName}-${n.engine}`),Engine:n.engine,EngineVersion:n.engineVersion,CacheNodeType:n.nodeType,NumCacheNodes:n.numCacheNodes,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[t.ref("CacheSecurityGroup")],Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n.engine}`)}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]})}function mn(e,n){if(!n.enabled)return;e.addResource("CloudFrontOriginAccessIdentity","AWS::CloudFront::CloudFrontOriginAccessIdentity",{CloudFrontOriginAccessIdentityConfig:{Comment:t.sub("${AWS::StackName} CloudFront OAI")}});let r=[],i=[];if(!n.origins||n.origins.length===0)r.push({Id:"S3Origin",DomainName:t.getAtt("StaticBucket","DomainName"),S3OriginConfig:{OriginAccessIdentity:t.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")}});else n.origins.forEach((c,u)=>{let d={Id:c.id,DomainName:c.domainName};if(c.originPath)d.OriginPath=c.originPath;if(c.domainName.includes("s3"))d.S3OriginConfig={OriginAccessIdentity:t.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")};else d.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"]};if(r.push(d),u>0||c.pathPattern)i.push({PathPattern:c.pathPattern||`/${c.id}/*`,TargetOriginId:c.id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:n.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:n.cachePolicy?.minTTL||0,DefaultTTL:n.cachePolicy?.defaultTTL||86400,MaxTTL:n.cachePolicy?.maxTTL||31536000})});let s={TargetOriginId:r[0].Id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:n.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:n.cachePolicy?.minTTL||0,DefaultTTL:n.cachePolicy?.defaultTTL||86400,MaxTTL:n.cachePolicy?.maxTTL||31536000};if(n.edgeFunctions&&n.edgeFunctions.length>0)s.LambdaFunctionAssociations=n.edgeFunctions.map((c)=>({EventType:c.eventType,LambdaFunctionARN:c.functionArn}));let a={Enabled:!0,HttpVersion:n.http3?"http3":"http2",IPV6Enabled:!0,Origins:r,DefaultCacheBehavior:s,PriceClass:n.priceClass||"PriceClass_100",ViewerCertificate:{}};if(i.length>0)a.CacheBehaviors=i;if(n.customDomain)a.Aliases=[n.customDomain.domain],a.ViewerCertificate={AcmCertificateArn:n.customDomain.certificateArn,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else a.ViewerCertificate={CloudFrontDefaultCertificate:!0};if(n.errorPages)a.CustomErrorResponses=Object.entries(n.errorPages).map(([c,u])=>({ErrorCode:Number.parseInt(c),ResponseCode:200,ResponsePagePath:u,ErrorCachingMinTTL:300}));if(a.DefaultRootObject="index.html",a.Comment=t.sub("${AWS::StackName} CloudFront Distribution"),e.addResource("CloudFrontDistribution","AWS::CloudFront::Distribution",{DistributionConfig:a},{dependsOn:"CloudFrontOriginAccessIdentity"}),!n.origins||n.origins.length===0)e.addResource("StaticBucketPolicyForCloudFront","AWS::S3::BucketPolicy",{Bucket:t.ref("StaticBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontAccess",Effect:"Allow",Principal:{CanonicalUser:t.getAtt("CloudFrontOriginAccessIdentity","S3CanonicalUserId")},Action:"s3:GetObject",Resource:t.join("",[t.getAtt("StaticBucket","Arn"),"/*"])}]}},{dependsOn:["StaticBucket","CloudFrontOriginAccessIdentity"]});if(n.customDomain)e.addResource("CloudFrontDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:t.sub(`${ti(n.customDomain.domain)}.`),Name:n.customDomain.domain,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:t.getAtt("CloudFrontDistribution","DomainName"),EvaluateTargetHealth:!1}},{dependsOn:"CloudFrontDistribution"});if(e.addOutputs({CloudFrontDistributionId:{Description:"CloudFront distribution ID",Value:t.ref("CloudFrontDistribution"),Export:{Name:t.sub("${AWS::StackName}-cloudfront-id")}},CloudFrontDomainName:{Description:"CloudFront distribution domain name",Value:t.getAtt("CloudFrontDistribution","DomainName"),Export:{Name:t.sub("${AWS::StackName}-cloudfront-domain")}}}),n.customDomain)e.addOutputs({CloudFrontURL:{Description:"CloudFront custom domain URL",Value:t.sub(`https://${n.customDomain.domain}`)}})}function ti(e){let n=e.split(".");if(n.length>=2)return n.slice(-2).join(".");return e}function gn(e,n){if(n.server)ni(e,n.server);if(n.fargate)pn(e,"app",n.fargate);if(n.services)n.services.forEach((r)=>{if(r.type==="fargate")pn(e,r.name,{taskDefinition:r.taskDefinition,service:r.service})})}function ni(e,n){if(!n)return;e.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for application instances",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:3000,ToPort:3000,SourceSecurityGroupId:t.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:t.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:t.sub("${AWS::StackName}-ec2-role")}]}),e.addResource("EC2InstanceProfile","AWS::IAM::InstanceProfile",{Roles:[t.ref("EC2InstanceRole")]},{dependsOn:"EC2InstanceRole"});let r=n.userData||`#!/bin/bash
|
|
2433
|
+
};`}var t={ref:(e)=>({Ref:e}),getAtt:(e,n)=>({"Fn::GetAtt":[e,n]}),join:(e,n)=>({"Fn::Join":[e,n]}),sub:(e,n)=>n?{"Fn::Sub":[e,n]}:{"Fn::Sub":e},select:(e,n)=>({"Fn::Select":[e,n]}),split:(e,n)=>({"Fn::Split":[e,n]}),getAZs:(e="")=>({"Fn::GetAZs":e}),importValue:(e)=>({"Fn::ImportValue":e}),findInMap:(e,n,r)=>({"Fn::FindInMap":[e,n,r]}),base64:(e)=>({"Fn::Base64":e}),cidr:(e,n,r)=>({"Fn::Cidr":[e,n,r]}),equals:(e,n)=>({"Fn::Equals":[e,n]}),if:(e,n,r)=>({"Fn::If":[e,n,r]}),not:(e)=>({"Fn::Not":[e]}),and:(...e)=>({"Fn::And":e}),or:(...e)=>({"Fn::Or":e})},Pn={s3Bucket:(e)=>t.sub(`arn:aws:s3:::${e}`),s3Object:(e,n="*")=>t.sub(`arn:aws:s3:::${e}/${n}`),lambda:(e,n,r)=>t.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${e}`,n&&r?{"AWS::Region":n,"AWS::AccountId":r}:void 0),dynamodb:(e)=>t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${e}`),sqs:(e)=>t.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${e}`),sns:(e)=>t.sub(`arn:aws:sns:\${AWS::Region}:\${AWS::AccountId}:${e}`),kinesis:(e)=>t.sub(`arn:aws:kinesis:\${AWS::Region}:\${AWS::AccountId}:stream/${e}`),iam:(e,n)=>t.sub(`arn:aws:iam::\${AWS::AccountId}:${e}/${n}`),secretsManager:(e)=>t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${e}`),cloudwatch:(e)=>t.sub(`arn:aws:logs:\${AWS::Region}:\${AWS::AccountId}:log-group:${e}`)},Gm={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 gn(e,n){if(n.type==="http")di(e,n);else if(n.type==="rest")mi(e,n);else if(n.type==="websocket")pi(e,n)}function di(e,n){let r={Name:t.sub("${AWS::StackName}-http-api"),ProtocolType:"HTTP"};if(n.cors)r.CorsConfiguration={AllowOrigins:n.cors.allowOrigins,AllowMethods:n.cors.allowMethods,AllowHeaders:n.cors.allowHeaders||["*"],MaxAge:n.cors.maxAge||300};if(e.addResource("HttpApi","AWS::ApiGatewayV2::Api",r),e.addResource("HttpApiStage","AWS::ApiGatewayV2::Stage",{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0,DefaultRouteSettings:n.throttling?{ThrottlingBurstLimit:n.throttling.burstLimit,ThrottlingRateLimit:n.throttling.rateLimit}:void 0,AccessLogSettings:{DestinationArn:t.getAtt("ApiLogGroup","Arn"),Format:"$context.requestId $context.error.message $context.error.messageString"}},{dependsOn:["HttpApi","ApiLogGroup"]}),e.addResource("ApiLogGroup","AWS::Logs::LogGroup",{LogGroupName:t.sub("/aws/apigateway/${AWS::StackName}-http-api"),RetentionInDays:14}),n.authorizer)gi(e,"HttpApi",n.authorizer);if(n.customDomain)vt(e,"HttpApi",n.customDomain,"HTTP");e.addOutputs({HttpApiId:{Description:"HTTP API ID",Value:t.ref("HttpApi"),Export:{Name:t.sub("${AWS::StackName}-http-api-id")}},HttpApiEndpoint:{Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint"),Export:{Name:t.sub("${AWS::StackName}-http-api-endpoint")}}})}function mi(e,n){e.addResource("RestApi","AWS::ApiGateway::RestApi",{Name:t.sub("${AWS::StackName}-rest-api"),Description:t.sub("REST API for ${AWS::StackName}"),EndpointConfiguration:{Types:["REGIONAL"]}}),e.addResource("ApiGatewayAccount","AWS::ApiGateway::Account",{CloudWatchRoleArn:t.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:t.ref("RestApi"),Description:"Initial deployment"},{dependsOn:"RestApi"});let r={RestApiId:t.ref("RestApi"),DeploymentId:t.ref("RestApiDeployment"),StageName:"prod",Description:"Production stage",MethodSettings:[{ResourcePath:"/*",HttpMethod:"*",LoggingLevel:"INFO",DataTraceEnabled:!0,MetricsEnabled:!0}]};if(n.throttling)r.MethodSettings[0].ThrottlingBurstLimit=n.throttling.burstLimit,r.MethodSettings[0].ThrottlingRateLimit=n.throttling.rateLimit;if(e.addResource("RestApiStage","AWS::ApiGateway::Stage",r,{dependsOn:["RestApi","RestApiDeployment"]}),n.customDomain)vt(e,"RestApi",n.customDomain,"REST");e.addOutputs({RestApiId:{Description:"REST API ID",Value:t.ref("RestApi"),Export:{Name:t.sub("${AWS::StackName}-rest-api-id")}},RestApiEndpoint:{Description:"REST API endpoint",Value:t.sub("https://${RestApi}.execute-api.${AWS::Region}.amazonaws.com/prod"),Export:{Name:t.sub("${AWS::StackName}-rest-api-endpoint")}}})}function pi(e,n){if(e.addResource("WebSocketApi","AWS::ApiGatewayV2::Api",{Name:t.sub("${AWS::StackName}-websocket-api"),ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action"}),n.routes){if(n.routes.connect)rt(e,"$connect",n.routes.connect.functionName);if(n.routes.disconnect)rt(e,"$disconnect",n.routes.disconnect.functionName);if(n.routes.default)rt(e,"$default",n.routes.default.functionName);if(n.routes.custom)n.routes.custom.forEach((r)=>{rt(e,r.routeKey,r.functionName)})}if(e.addResource("WebSocketApiStage","AWS::ApiGatewayV2::Stage",{ApiId:t.ref("WebSocketApi"),StageName:"prod",AutoDeploy:!0,DefaultRouteSettings:n.throttling?{ThrottlingBurstLimit:n.throttling.burstLimit,ThrottlingRateLimit:n.throttling.rateLimit}:void 0},{dependsOn:"WebSocketApi"}),n.customDomain)vt(e,"WebSocketApi",n.customDomain,"WEBSOCKET");e.addOutputs({WebSocketApiId:{Description:"WebSocket API ID",Value:t.ref("WebSocketApi"),Export:{Name:t.sub("${AWS::StackName}-websocket-api-id")}},WebSocketApiEndpoint:{Description:"WebSocket API endpoint",Value:t.getAtt("WebSocketApi","ApiEndpoint"),Export:{Name:t.sub("${AWS::StackName}-websocket-api-endpoint")}}})}function rt(e,n,r){let i=e.toLogicalId(`websocket-route-${n}`),s=e.toLogicalId(`websocket-integration-${n}`),a=e.toLogicalId(`${r}-function`);e.addResource(s,"AWS::ApiGatewayV2::Integration",{ApiId:t.ref("WebSocketApi"),IntegrationType:"AWS_PROXY",IntegrationUri:t.sub(`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${a}.Arn}/invocations`)},{dependsOn:["WebSocketApi",a]}),e.addResource(i,"AWS::ApiGatewayV2::Route",{ApiId:t.ref("WebSocketApi"),RouteKey:n,Target:t.join("/",["integrations",t.ref(s)])},{dependsOn:["WebSocketApi",s]}),e.addResource(`${i}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(a),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*")},{dependsOn:[a,"WebSocketApi"]})}function vt(e,n,r,i){let s={DomainName:r.domain};if(i==="REST")s.CertificateArn=r.certificateArn,s.EndpointConfiguration={Types:["REGIONAL"]},e.addResource("ApiCustomDomain","AWS::ApiGateway::DomainName",s),e.addResource("ApiBasePathMapping","AWS::ApiGateway::BasePathMapping",{DomainName:t.ref("ApiCustomDomain"),RestApiId:t.ref(n),Stage:t.ref("RestApiStage")},{dependsOn:["ApiCustomDomain",n,"RestApiStage"]});else s.DomainNameConfigurations=[{CertificateArn:r.certificateArn,EndpointType:"REGIONAL"}],e.addResource("ApiCustomDomain","AWS::ApiGatewayV2::DomainName",s),e.addResource("ApiMapping","AWS::ApiGatewayV2::ApiMapping",{ApiId:t.ref(n),DomainName:t.ref("ApiCustomDomain"),Stage:i==="HTTP"?t.ref("HttpApiStage"):t.ref("WebSocketApiStage")},{dependsOn:["ApiCustomDomain",n]});if(r.dnsProvider!=="external")e.addResource("ApiDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:t.sub(`${yi(r.domain)}.`),Name:r.domain,Type:"A",AliasTarget:{HostedZoneId:t.getAtt("ApiCustomDomain","RegionalHostedZoneId"),DNSName:t.getAtt("ApiCustomDomain","RegionalDomainName"),EvaluateTargetHealth:!1}},{dependsOn:"ApiCustomDomain"});e.addOutputs({ApiCustomDomainName:{Description:"Configured API custom domain",Value:r.domain},ApiCustomDomainTarget:{Description:"DNS target for Route53 or an external DNS provider",Value:t.getAtt("ApiCustomDomain","RegionalDomainName")},ApiCustomDomainHostedZoneId:{Description:"Regional API Gateway hosted zone ID",Value:t.getAtt("ApiCustomDomain","RegionalHostedZoneId")}})}function gi(e,n,r){if(!r)return;if(r.type==="jwt")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:t.ref(n),AuthorizerType:"JWT",IdentitySource:[r.identitySource||"$request.header.Authorization"],JwtConfiguration:{Issuer:r.issuer,Audience:r.audience},Name:"JWTAuthorizer"},{dependsOn:n});else if(r.type==="lambda")e.addResource("ApiAuthorizer","AWS::ApiGatewayV2::Authorizer",{ApiId:t.ref(n),AuthorizerType:"REQUEST",AuthorizerUri:r.authorizerUri,IdentitySource:[r.identitySource||"$request.header.Authorization"],Name:"LambdaAuthorizer"},{dependsOn:n})}function yi(e){let n=e.split(".");if(n.length>=2)return n.slice(-2).join(".");return e}function yn(e,n){if(n.redis)fi(e,n.redis);if(n.memcached)hi(e,n.memcached);if(n.elasticache)bi(e,n.elasticache)}function fi(e,n){if(!n)return;if(e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache Redis cluster",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Redis",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:n.port||6379,ToPort:n.port||6379,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]}),n.parameterGroup&&Object.keys(n.parameterGroup).length>0)e.addResource("CacheParameterGroup","AWS::ElastiCache::ParameterGroup",{Description:"Parameter group for Redis",CacheParameterGroupFamily:`redis${n.engineVersion.split(".")[0]}`,Properties:n.parameterGroup});if(n.numCacheNodes>1||n.automaticFailoverEnabled)e.addResource("RedisReplicationGroup","AWS::ElastiCache::ReplicationGroup",{ReplicationGroupDescription:"Redis replication group",ReplicationGroupId:t.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:n.engineVersion,CacheNodeType:n.nodeType,NumCacheClusters:n.numCacheNodes,AutomaticFailoverEnabled:n.automaticFailoverEnabled||!1,MultiAZEnabled:n.automaticFailoverEnabled||!1,Port:n.port||6379,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.ref("CacheSecurityGroup")],CacheParameterGroupName:n.parameterGroup?t.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:n.snapshotRetentionLimit||5,SnapshotWindow:n.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",AtRestEncryptionEnabled:!0,TransitEncryptionEnabled:!0,Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-redis")}]},{dependsOn:n.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis primary endpoint",Value:t.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address"),Export:{Name:t.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:t.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port"),Export:{Name:t.sub("${AWS::StackName}-redis-port")}}});else e.addResource("RedisCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:t.sub("${AWS::StackName}-redis"),Engine:"redis",EngineVersion:n.engineVersion,CacheNodeType:n.nodeType,NumCacheNodes:1,Port:n.port||6379,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[t.ref("CacheSecurityGroup")],CacheParameterGroupName:n.parameterGroup?t.ref("CacheParameterGroup"):void 0,SnapshotRetentionLimit:n.snapshotRetentionLimit||5,SnapshotWindow:n.snapshotWindow||"03:00-05:00",PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-redis")}]},{dependsOn:n.parameterGroup?["CacheSubnetGroup","CacheSecurityGroup","CacheParameterGroup"]:["CacheSubnetGroup","CacheSecurityGroup"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addOutputs({RedisEndpoint:{Description:"Redis endpoint",Value:t.getAtt("RedisCacheCluster","RedisEndpoint.Address"),Export:{Name:t.sub("${AWS::StackName}-redis-endpoint")}},RedisPort:{Description:"Redis port",Value:t.getAtt("RedisCacheCluster","RedisEndpoint.Port"),Export:{Name:t.sub("${AWS::StackName}-redis-port")}}})}function hi(e,n){if(!n)return;if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache Memcached",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:n.port||11211,ToPort:n.port||11211,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("MemcachedCacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:t.sub("${AWS::StackName}-memcached"),Engine:"memcached",EngineVersion:n.engineVersion,CacheNodeType:n.nodeType,NumCacheNodes:n.numCacheNodes,Port:n.port||11211,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[t.ref("CacheSecurityGroup")],PreferredMaintenanceWindow:"sun:05:00-sun:06:00",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-memcached")}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]}),e.addOutputs({MemcachedEndpoint:{Description:"Memcached configuration endpoint",Value:t.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Address"),Export:{Name:t.sub("${AWS::StackName}-memcached-endpoint")}},MemcachedPort:{Description:"Memcached port",Value:t.getAtt("MemcachedCacheCluster","ConfigurationEndpoint.Port"),Export:{Name:t.sub("${AWS::StackName}-memcached-port")}}})}function bi(e,n){if(!n)return;let r=n.engine==="redis";if(!e.hasResource("CacheSubnetGroup"))e.addResource("CacheSubnetGroup","AWS::ElastiCache::SubnetGroup",{Description:"Subnet group for ElastiCache",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]});if(!e.hasResource("CacheSecurityGroup"))e.addResource("CacheSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for ElastiCache",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:r?6379:11211,ToPort:r?6379:11211,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cache-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});e.addResource("CacheCluster","AWS::ElastiCache::CacheCluster",{ClusterName:t.sub(`\${AWS::StackName}-${n.engine}`),Engine:n.engine,EngineVersion:n.engineVersion,CacheNodeType:n.nodeType,NumCacheNodes:n.numCacheNodes,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),VpcSecurityGroupIds:[t.ref("CacheSecurityGroup")],Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n.engine}`)}]},{dependsOn:["CacheSubnetGroup","CacheSecurityGroup"]})}function fn(e,n){if(!n.enabled)return;e.addResource("CloudFrontOriginAccessIdentity","AWS::CloudFront::CloudFrontOriginAccessIdentity",{CloudFrontOriginAccessIdentityConfig:{Comment:t.sub("${AWS::StackName} CloudFront OAI")}});let r=[],i=[];if(!n.origins||n.origins.length===0)r.push({Id:"S3Origin",DomainName:t.getAtt("StaticBucket","DomainName"),S3OriginConfig:{OriginAccessIdentity:t.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")}});else n.origins.forEach((c,u)=>{let d={Id:c.id,DomainName:c.domainName};if(c.originPath)d.OriginPath=c.originPath;if(c.domainName.includes("s3"))d.S3OriginConfig={OriginAccessIdentity:t.sub("origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}")};else d.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"]};if(r.push(d),u>0||c.pathPattern)i.push({PathPattern:c.pathPattern||`/${c.id}/*`,TargetOriginId:c.id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:n.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:n.cachePolicy?.minTTL||0,DefaultTTL:n.cachePolicy?.defaultTTL||86400,MaxTTL:n.cachePolicy?.maxTTL||31536000})});let s={TargetOriginId:r[0].Id,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD"],Compress:n.compress!==!1,ForwardedValues:{QueryString:!0,Cookies:{Forward:"none"}},MinTTL:n.cachePolicy?.minTTL||0,DefaultTTL:n.cachePolicy?.defaultTTL||86400,MaxTTL:n.cachePolicy?.maxTTL||31536000};if(n.edgeFunctions&&n.edgeFunctions.length>0)s.LambdaFunctionAssociations=n.edgeFunctions.map((c)=>({EventType:c.eventType,LambdaFunctionARN:c.functionArn}));let a={Enabled:!0,HttpVersion:n.http3?"http3":"http2",IPV6Enabled:!0,Origins:r,DefaultCacheBehavior:s,PriceClass:n.priceClass||"PriceClass_100",ViewerCertificate:{}};if(i.length>0)a.CacheBehaviors=i;if(n.customDomain)a.Aliases=[n.customDomain.domain],a.ViewerCertificate={AcmCertificateArn:n.customDomain.certificateArn,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else a.ViewerCertificate={CloudFrontDefaultCertificate:!0};if(n.errorPages)a.CustomErrorResponses=Object.entries(n.errorPages).map(([c,u])=>({ErrorCode:Number.parseInt(c),ResponseCode:200,ResponsePagePath:u,ErrorCachingMinTTL:300}));if(a.DefaultRootObject="index.html",a.Comment=t.sub("${AWS::StackName} CloudFront Distribution"),e.addResource("CloudFrontDistribution","AWS::CloudFront::Distribution",{DistributionConfig:a},{dependsOn:"CloudFrontOriginAccessIdentity"}),!n.origins||n.origins.length===0)e.addResource("StaticBucketPolicyForCloudFront","AWS::S3::BucketPolicy",{Bucket:t.ref("StaticBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontAccess",Effect:"Allow",Principal:{CanonicalUser:t.getAtt("CloudFrontOriginAccessIdentity","S3CanonicalUserId")},Action:"s3:GetObject",Resource:t.join("",[t.getAtt("StaticBucket","Arn"),"/*"])}]}},{dependsOn:["StaticBucket","CloudFrontOriginAccessIdentity"]});if(n.customDomain)e.addResource("CloudFrontDNSRecord","AWS::Route53::RecordSet",{HostedZoneName:t.sub(`${Si(n.customDomain.domain)}.`),Name:n.customDomain.domain,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:t.getAtt("CloudFrontDistribution","DomainName"),EvaluateTargetHealth:!1}},{dependsOn:"CloudFrontDistribution"});if(e.addOutputs({CloudFrontDistributionId:{Description:"CloudFront distribution ID",Value:t.ref("CloudFrontDistribution"),Export:{Name:t.sub("${AWS::StackName}-cloudfront-id")}},CloudFrontDomainName:{Description:"CloudFront distribution domain name",Value:t.getAtt("CloudFrontDistribution","DomainName"),Export:{Name:t.sub("${AWS::StackName}-cloudfront-domain")}}}),n.customDomain)e.addOutputs({CloudFrontURL:{Description:"CloudFront custom domain URL",Value:t.sub(`https://${n.customDomain.domain}`)}})}function Si(e){let n=e.split(".");if(n.length>=2)return n.slice(-2).join(".");return e}function bn(e,n){if(n.server)Ai(e,n.server);if(n.fargate)hn(e,"app",n.fargate);if(n.services)n.services.forEach((r)=>{if(r.type==="fargate")hn(e,r.name,{taskDefinition:r.taskDefinition,service:r.service})})}function Ai(e,n){if(!n)return;e.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for application instances",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:3000,ToPort:3000,SourceSecurityGroupId:t.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:t.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:t.sub("${AWS::StackName}-ec2-role")}]}),e.addResource("EC2InstanceProfile","AWS::IAM::InstanceProfile",{Roles:[t.ref("EC2InstanceRole")]},{dependsOn:"EC2InstanceRole"});let r=n.userData||`#!/bin/bash
|
|
2434
2434
|
set -e
|
|
2435
2435
|
# Update system
|
|
2436
2436
|
yum update -y || apt-get update -y
|
|
@@ -2445,20 +2445,18 @@ rpm -U ./amazon-cloudwatch-agent.rpm || true
|
|
|
2445
2445
|
|
|
2446
2446
|
# Signal completion
|
|
2447
2447
|
/opt/aws/bin/cfn-signal -e $? --stack \${AWS::StackName} --resource AutoScalingGroup --region \${AWS::Region}
|
|
2448
|
-
`;if(e.addResource("LaunchTemplate","AWS::EC2::LaunchTemplate",{LaunchTemplateName:t.sub("${AWS::StackName}-template"),LaunchTemplateData:{ImageId:n.ami||t.findInMap("RegionMap",t.ref("AWS::Region"),"AMI"),InstanceType:n.instanceType,IamInstanceProfile:{Arn:t.getAtt("EC2InstanceProfile","Arn")},SecurityGroupIds:[t.ref("AppSecurityGroup")],UserData:t.base64(t.sub(r)),TagSpecifications:[{ResourceType:"instance",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-instance")}]}],MetadataOptions:{HttpTokens:"required",HttpPutResponseHopLimit:1}}},{dependsOn:["AppSecurityGroup","EC2InstanceProfile"]}),n.loadBalancer){ri(e,n.loadBalancer);let i={LaunchTemplate:{LaunchTemplateId:t.ref("LaunchTemplate"),Version:t.getAtt("LaunchTemplate","LatestVersionNumber")},MinSize:n.autoScaling?.min.toString()||"1",MaxSize:n.autoScaling?.max.toString()||"3",DesiredCapacity:n.autoScaling?.min.toString()||"2",VPCZoneIdentifier:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],TargetGroupARNs:[t.ref("TargetGroup")],HealthCheckType:"ELB",HealthCheckGracePeriod:300,Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-asg"),PropagateAtLaunch:!0}]};if(e.addResource("AutoScalingGroup","AWS::AutoScaling::AutoScalingGroup",i,{dependsOn:["LaunchTemplate","TargetGroup"]}),n.autoScaling)e.addResource("ScaleUpPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:t.ref("AutoScalingGroup"),Cooldown:n.autoScaling.scaleUpCooldown?.toString()||"300",ScalingAdjustment:"1"},{dependsOn:"AutoScalingGroup"}),e.addResource("ScaleDownPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:t.ref("AutoScalingGroup"),Cooldown:n.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:(n.autoScaling.targetCPU||70).toString(),AlarmActions:[t.ref("ScaleUpPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:t.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:((n.autoScaling.targetCPU||70)-20).toString(),AlarmActions:[t.ref("ScaleDownPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:t.ref("AutoScalingGroup")}],ComparisonOperator:"LessThanThreshold"},{dependsOn:["AutoScalingGroup","ScaleDownPolicy"]})}}function ri(e,n){if(!n)return;e.addResource("ALBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for Application Load Balancer",VpcId:t.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:t.sub("${AWS::StackName}-alb-sg")}]},{dependsOn:"VPC"}),e.addResource("LoadBalancer","AWS::ElasticLoadBalancingV2::LoadBalancer",{Name:t.sub("${AWS::StackName}-alb"),Type:n.type||"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[t.ref("PublicSubnet1"),t.ref("PublicSubnet2")],SecurityGroups:[t.ref("ALBSecurityGroup")],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-alb")}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]}),e.addResource("TargetGroup","AWS::ElasticLoadBalancingV2::TargetGroup",{Name:t.sub("${AWS::StackName}-tg"),Port:3000,Protocol:"HTTP",VpcId:t.ref("VPC"),HealthCheckEnabled:!0,HealthCheckPath:n.healthCheck?.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:n.healthCheck?.interval||30,HealthCheckTimeoutSeconds:n.healthCheck?.timeout||5,HealthyThresholdCount:n.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:n.healthCheck?.unhealthyThreshold||3,TargetType:"instance",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-tg")}]},{dependsOn:"VPC"}),e.addResource("LoadBalancerListener","AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:t.ref("LoadBalancer"),Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:t.ref("TargetGroup")}]},{dependsOn:["LoadBalancer","TargetGroup"]}),e.addOutputs({LoadBalancerDNS:{Description:"Load Balancer DNS Name",Value:t.getAtt("LoadBalancer","DNSName"),Export:{Name:t.sub("${AWS::StackName}-alb-dns")}}})}function pn(e,n,r){let i=e.toLogicalId(n),s=r.taskDefinition.containerDefinitions?.[0],a=s?.name||s?.Name||n,c=s?.portMappings?.[0]?.containerPort||s?.PortMappings?.[0]?.ContainerPort||3000,u=(r.taskDefinition.containerDefinitions||[]).flatMap((y)=>(y.secrets||y.Secrets||[]).map((f)=>f.valueFrom||f.ValueFrom)).filter(Boolean);if(!e.hasResource("ECSCluster"))e.addResource("ECSCluster","AWS::ECS::Cluster",{ClusterName:t.sub("${AWS::StackName}-cluster"),Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cluster")}]});if(e.addResource(`${i}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"],...u.length?{Policies:[{PolicyName:"read-task-secrets",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameters"],Resource:u},{Effect:"Allow",Action:"kms:Decrypt",Resource:"*"}]}}]}:{}}),e.addResource(`${i}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:t.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:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0"},...r.loadBalancer?.customDomain?.certificateArn?[{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0"}]:[]],SecurityGroupEgress:[{IpProtocol:"tcp",FromPort:c,ToPort:c,CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:t.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:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:c,ToPort:c,SourceSecurityGroupId:t.ref("ALBSecurityGroup")}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-app-sg")}]},{dependsOn:["VPC","ALBSecurityGroup"]});let d=(r.taskDefinition.containerDefinitions||[{name:n,image:t.sub(`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${n}:latest`),portMappings:[{containerPort:3000}]}]).map((y)=>({Name:y.Name||y.name,Image:y.Image||y.image,Essential:y.Essential??y.essential??!0,PortMappings:(y.PortMappings||y.portMappings||[]).map((f)=>({ContainerPort:f.ContainerPort??f.containerPort,Protocol:f.Protocol||f.protocol||"tcp"})),Environment:Array.isArray(y.Environment||y.environment)?(y.Environment||y.environment).map((f)=>({Name:f.Name||f.name,Value:f.Value??f.value})):Object.entries(y.Environment||y.environment||{}).map(([f,h])=>({Name:f,Value:h})),Secrets:(y.Secrets||y.secrets||[]).map((f)=>({Name:f.Name||f.name,ValueFrom:f.ValueFrom||f.valueFrom})),HealthCheck:y.HealthCheck||y.healthCheck,Command:y.Command||y.command,EntryPoint:y.EntryPoint||y.entryPoint,LogConfiguration:y.LogConfiguration||y.logConfiguration||{LogDriver:"awslogs",Options:{"awslogs-group":t.ref(`${i}LogGroup`),"awslogs-region":t.ref("AWS::Region"),"awslogs-stream-prefix":n}}}));e.addResource(`${i}TaskDefinition`,"AWS::ECS::TaskDefinition",{Family:t.sub(`\${AWS::StackName}-${n}`),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:r.taskDefinition.cpu,Memory:r.taskDefinition.memory,ExecutionRoleArn:t.getAtt(`${i}TaskExecutionRole`,"Arn"),TaskRoleArn:t.getAtt(`${i}TaskRole`,"Arn"),ContainerDefinitions:d},{dependsOn:[`${i}TaskExecutionRole`,`${i}TaskRole`,`${i}LogGroup`]}),e.addResource(`${i}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:t.sub(`/ecs/\${AWS::StackName}/${n}`),RetentionInDays:14});let m=r.service.healthCheck||{};e.addResource(`${i}TargetGroup`,"AWS::ElasticLoadBalancingV2::TargetGroup",{VpcId:t.ref("VPC"),Port:c,Protocol:"HTTP",TargetType:"ip",HealthCheckEnabled:!0,HealthCheckPath:m.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:m.interval||30,HealthCheckTimeoutSeconds:m.timeout||5,HealthyThresholdCount:m.healthyThreshold||2,UnhealthyThresholdCount:m.unhealthyThreshold||3,Matcher:{HttpCode:"200-399"},TargetGroupAttributes:[{Key:"deregistration_delay.timeout_seconds",Value:"30"}]},{dependsOn:"VPC"}),e.addResource(`${i}LoadBalancer`,"AWS::ElasticLoadBalancingV2::LoadBalancer",{Type:"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[t.ref("PublicSubnet1"),t.ref("PublicSubnet2")],SecurityGroups:[t.ref("ALBSecurityGroup")],LoadBalancerAttributes:[{Key:"routing.http.drop_invalid_header_fields.enabled",Value:"true"},{Key:"deletion_protection.enabled",Value:String(r.loadBalancer?.deletionProtection===!0)}],Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}-alb`)}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]});let p=r.loadBalancer?.customDomain?.certificateArn,g=r.loadBalancer?.originVerifyHeader;if(e.addResource(`${i}HttpListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:t.ref(`${i}LoadBalancer`),Port:80,Protocol:"HTTP",DefaultActions:p?[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]:g?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:t.ref(`${i}TargetGroup`)}]},{dependsOn:[`${i}LoadBalancer`,`${i}TargetGroup`]}),p)e.addResource(`${i}HttpsListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:t.ref(`${i}LoadBalancer`),Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:p}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06",DefaultActions:g?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:t.ref(`${i}TargetGroup`)}]},{dependsOn:[`${i}LoadBalancer`,`${i}TargetGroup`]});if(g){let y=p?`${i}HttpsListener`:`${i}HttpListener`;e.addResource(`${i}OriginVerifyRule`,"AWS::ElasticLoadBalancingV2::ListenerRule",{ListenerArn:t.ref(y),Priority:1,Conditions:[{Field:"http-header",HttpHeaderConfig:{HttpHeaderName:g.name,Values:[g.value]}}],Actions:[{Type:"forward",TargetGroupArn:t.ref(`${i}TargetGroup`)}]},{dependsOn:[y,`${i}TargetGroup`]})}if(e.addResource(`${i}Service`,"AWS::ECS::Service",{ServiceName:t.sub(`\${AWS::StackName}-${n}`),Cluster:t.ref("ECSCluster"),TaskDefinition:t.ref(`${i}TaskDefinition`),DesiredCount:r.service.desiredCount,LaunchType:"FARGATE",PlatformVersion:"LATEST",HealthCheckGracePeriodSeconds:60,DeploymentConfiguration:{MinimumHealthyPercent:100,MaximumPercent:200,DeploymentCircuitBreaker:{Enable:!0,Rollback:!0}},LoadBalancers:[{ContainerName:a,ContainerPort:c,TargetGroupArn:t.ref(`${i}TargetGroup`)}],NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"DISABLED",Subnets:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],SecurityGroups:[t.ref("AppSecurityGroup")]}}},{dependsOn:["ECSCluster",`${i}TaskDefinition`,g?`${i}OriginVerifyRule`:p?`${i}HttpsListener`:`${i}HttpListener`]}),r.service.autoScaling){let y=r.service.autoScaling;e.addResource(`${i}ScalableTarget`,"AWS::ApplicationAutoScaling::ScalableTarget",{MinCapacity:y.min,MaxCapacity:y.max,ResourceId:t.join("/",["service",t.ref("ECSCluster"),t.getAtt(`${i}Service`,"Name")]),RoleARN:t.sub("arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"),ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs"},{dependsOn:`${i}Service`}),e.addResource(`${i}ScalingPolicy`,"AWS::ApplicationAutoScaling::ScalingPolicy",{PolicyType:"TargetTrackingScaling",ScalingTargetId:t.ref(`${i}ScalableTarget`),TargetTrackingScalingPolicyConfiguration:{TargetValue:y.targetCPU||70,PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},ScaleInCooldown:60,ScaleOutCooldown:30}},{dependsOn:`${i}ScalableTarget`})}e.addOutputs({[`${i}ClusterName`]:{Description:"ECS cluster name",Value:t.ref("ECSCluster")},[`${i}ServiceName`]:{Description:"ECS service name",Value:t.getAtt(`${i}Service`,"Name")},[`${i}LoadBalancerDnsName`]:{Description:"ALB origin hostname",Value:t.getAtt(`${i}LoadBalancer`,"DNSName")},[`${i}LoadBalancerHostedZoneId`]:{Description:"ALB canonical hosted zone ID",Value:t.getAtt(`${i}LoadBalancer`,"CanonicalHostedZoneID")},[`${i}TargetGroupArn`]:{Description:"ECS target group ARN",Value:t.ref(`${i}TargetGroup`)}})}function fn(e,n){if(n.postgres)yn(e,"postgres",n.postgres);if(n.mysql)yn(e,"mysql",n.mysql);if(n.dynamodb?.tables)n.dynamodb.tables.forEach((r)=>{ii(e,r)})}function yn(e,n,r){if(!r)return;let i=n==="postgres"?"postgres":"mysql",s=e.toLogicalId(`${i}-db`);e.addResource("DBSubnetGroup","AWS::RDS::DBSubnetGroup",{DBSubnetGroupDescription:"Subnet group for RDS instance",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-db-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("DBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for RDS instance",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:n==="postgres"?5432:3306,ToPort:n==="postgres"?5432:3306,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-db-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});let a=n==="postgres"?`postgres${r.version.split(".")[0]}`:`mysql${r.version.split(".")[0]}.${r.version.split(".")[1]||"0"}`;if(r.parameters&&Object.keys(r.parameters).length>0)e.addResource("DBParameterGroup","AWS::RDS::DBParameterGroup",{Description:`Parameter group for ${i}`,Family:a,Parameters:r.parameters,Tags:[{Key:"Name",Value:t.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:t.sub("${AWS::StackName}-db-secret")}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"});let c={Engine:i,EngineVersion:r.version,DBInstanceClass:r.instanceClass,AllocatedStorage:r.allocatedStorage.toString(),MaxAllocatedStorage:r.maxAllocatedStorage?.toString(),StorageType:"gp3",StorageEncrypted:!0,MultiAZ:r.multiAZ!==!1,DBSubnetGroupName:t.ref("DBSubnetGroup"),VPCSecurityGroups:[t.ref("DBSecurityGroup")],MasterUsername:t.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:username}}"),MasterUserPassword:t.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:password}}"),BackupRetentionPeriod:r.backupRetentionDays||7,PreferredBackupWindow:r.preferredBackupWindow||"03:00-04:00",PreferredMaintenanceWindow:r.preferredMaintenanceWindow||"sun:04:00-sun:05:00",EnablePerformanceInsights:r.enablePerformanceInsights!==!1,PerformanceInsightsRetentionPeriod:r.performanceInsightsRetention||7,DeletionProtection:r.deletionProtection!==!1,CopyTagsToSnapshot:!0,EnableCloudwatchLogsExports:n==="postgres"?["postgresql"]:["error","general","slowquery"],Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${i}-db`)}]};if(r.parameters&&Object.keys(r.parameters).length>0)c.DBParameterGroupName=t.ref("DBParameterGroup");e.addResource(s,"AWS::RDS::DBInstance",c,{dependsOn:["DBSubnetGroup","DBSecurityGroup","DBSecret"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addResource("DBSecretAttachment","AWS::SecretsManager::SecretTargetAttachment",{SecretId:t.ref("DBSecret"),TargetId:t.ref(s),TargetType:"AWS::RDS::DBInstance"},{dependsOn:[s,"DBSecret"]}),e.addOutputs({DBEndpoint:{Description:"Database endpoint",Value:t.getAtt(s,"Endpoint.Address"),Export:{Name:t.sub("${AWS::StackName}-db-endpoint")}},DBPort:{Description:"Database port",Value:t.getAtt(s,"Endpoint.Port"),Export:{Name:t.sub("${AWS::StackName}-db-port")}},DBSecretArn:{Description:"ARN of the database credentials secret",Value:t.ref("DBSecret"),Export:{Name:t.sub("${AWS::StackName}-db-secret-arn")}}})}function ii(e,n){let r=e.toLogicalId(`${n.name}-table`),i={TableName:t.sub(`\${AWS::StackName}-${n.name}`),BillingMode:n.billingMode||"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:n.partitionKey,AttributeType:"S"}],KeySchema:[{AttributeName:n.partitionKey,KeyType:"HASH"}],Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n.name}`)}]};if(n.sortKey)i.AttributeDefinitions.push({AttributeName:n.sortKey,AttributeType:"S"}),i.KeySchema.push({AttributeName:n.sortKey,KeyType:"RANGE"});if(n.billingMode==="PROVISIONED")i.ProvisionedThroughput={ReadCapacityUnits:n.readCapacity||5,WriteCapacityUnits:n.writeCapacity||5};if(n.streamEnabled)i.StreamSpecification={StreamViewType:"NEW_AND_OLD_IMAGES"};if(n.pointInTimeRecovery)i.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(n.ttl?.enabled)i.TimeToLiveSpecification={Enabled:!0,AttributeName:n.ttl.attributeName};if(n.globalSecondaryIndexes&&n.globalSecondaryIndexes.length>0)i.GlobalSecondaryIndexes=n.globalSecondaryIndexes.map((s)=>{let a=new Set(i.AttributeDefinitions.map((u)=>u.AttributeName));if(!a.has(s.partitionKey))i.AttributeDefinitions.push({AttributeName:s.partitionKey,AttributeType:"S"});if(s.sortKey&&!a.has(s.sortKey))i.AttributeDefinitions.push({AttributeName:s.sortKey,AttributeType:"S"});let c={IndexName:s.name,KeySchema:[{AttributeName:s.partitionKey,KeyType:"HASH"}],Projection:{ProjectionType:s.projectionType||"ALL"}};if(s.sortKey)c.KeySchema.push({AttributeName:s.sortKey,KeyType:"RANGE"});if(s.projectionType==="INCLUDE"&&s.nonKeyAttributes)c.Projection.NonKeyAttributes=s.nonKeyAttributes;if(n.billingMode==="PROVISIONED")c.ProvisionedThroughput={ReadCapacityUnits:n.readCapacity||5,WriteCapacityUnits:n.writeCapacity||5};return c});if(e.addResource(r,"AWS::DynamoDB::Table",i,{deletionPolicy:"Retain"}),e.addOutputs({[`${r}Name`]:{Description:`${n.name} table name`,Value:t.ref(r),Export:{Name:t.sub(`\${AWS::StackName}-${n.name}-table`)}},[`${r}Arn`]:{Description:`${n.name} table ARN`,Value:t.getAtt(r,"Arn"),Export:{Name:t.sub(`\${AWS::StackName}-${n.name}-table-arn`)}}}),n.streamEnabled)e.addOutputs({[`${r}StreamArn`]:{Description:`${n.name} stream ARN`,Value:t.getAtt(r,"StreamArn"),Export:{Name:t.sub(`\${AWS::StackName}-${n.name}-stream-arn`)}}})}function hn(e,n){for(let[r,i]of Object.entries(n))i.forEach((s)=>{si(e,s,r)})}function si(e,n,r){let i=e.toLogicalId(`${r}-${n.name}-function`),s=`${i}Role`;e.addResource(s,"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:[...oi(n.events||[])]}}],Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n.name}-role`)}]});let a={FunctionName:t.sub(`\${AWS::StackName}-${n.name}`),Runtime:n.runtime,Handler:n.handler,Role:t.getAtt(s,"Arn"),MemorySize:n.memory,Timeout:n.timeout,Code:{ZipFile:`exports.handler = async (event) => {
|
|
2448
|
+
`;if(e.addResource("LaunchTemplate","AWS::EC2::LaunchTemplate",{LaunchTemplateName:t.sub("${AWS::StackName}-template"),LaunchTemplateData:{ImageId:n.ami||t.findInMap("RegionMap",t.ref("AWS::Region"),"AMI"),InstanceType:n.instanceType,IamInstanceProfile:{Arn:t.getAtt("EC2InstanceProfile","Arn")},SecurityGroupIds:[t.ref("AppSecurityGroup")],UserData:t.base64(t.sub(r)),TagSpecifications:[{ResourceType:"instance",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-instance")}]}],MetadataOptions:{HttpTokens:"required",HttpPutResponseHopLimit:1}}},{dependsOn:["AppSecurityGroup","EC2InstanceProfile"]}),n.loadBalancer){Ci(e,n.loadBalancer);let i={LaunchTemplate:{LaunchTemplateId:t.ref("LaunchTemplate"),Version:t.getAtt("LaunchTemplate","LatestVersionNumber")},MinSize:n.autoScaling?.min.toString()||"1",MaxSize:n.autoScaling?.max.toString()||"3",DesiredCapacity:n.autoScaling?.min.toString()||"2",VPCZoneIdentifier:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],TargetGroupARNs:[t.ref("TargetGroup")],HealthCheckType:"ELB",HealthCheckGracePeriod:300,Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-asg"),PropagateAtLaunch:!0}]};if(e.addResource("AutoScalingGroup","AWS::AutoScaling::AutoScalingGroup",i,{dependsOn:["LaunchTemplate","TargetGroup"]}),n.autoScaling)e.addResource("ScaleUpPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:t.ref("AutoScalingGroup"),Cooldown:n.autoScaling.scaleUpCooldown?.toString()||"300",ScalingAdjustment:"1"},{dependsOn:"AutoScalingGroup"}),e.addResource("ScaleDownPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:t.ref("AutoScalingGroup"),Cooldown:n.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:(n.autoScaling.targetCPU||70).toString(),AlarmActions:[t.ref("ScaleUpPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:t.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:((n.autoScaling.targetCPU||70)-20).toString(),AlarmActions:[t.ref("ScaleDownPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:t.ref("AutoScalingGroup")}],ComparisonOperator:"LessThanThreshold"},{dependsOn:["AutoScalingGroup","ScaleDownPolicy"]})}}function Ci(e,n){if(!n)return;e.addResource("ALBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for Application Load Balancer",VpcId:t.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:t.sub("${AWS::StackName}-alb-sg")}]},{dependsOn:"VPC"}),e.addResource("LoadBalancer","AWS::ElasticLoadBalancingV2::LoadBalancer",{Name:t.sub("${AWS::StackName}-alb"),Type:n.type||"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[t.ref("PublicSubnet1"),t.ref("PublicSubnet2")],SecurityGroups:[t.ref("ALBSecurityGroup")],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-alb")}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]}),e.addResource("TargetGroup","AWS::ElasticLoadBalancingV2::TargetGroup",{Name:t.sub("${AWS::StackName}-tg"),Port:3000,Protocol:"HTTP",VpcId:t.ref("VPC"),HealthCheckEnabled:!0,HealthCheckPath:n.healthCheck?.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:n.healthCheck?.interval||30,HealthCheckTimeoutSeconds:n.healthCheck?.timeout||5,HealthyThresholdCount:n.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:n.healthCheck?.unhealthyThreshold||3,TargetType:"instance",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-tg")}]},{dependsOn:"VPC"}),e.addResource("LoadBalancerListener","AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:t.ref("LoadBalancer"),Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:t.ref("TargetGroup")}]},{dependsOn:["LoadBalancer","TargetGroup"]}),e.addOutputs({LoadBalancerDNS:{Description:"Load Balancer DNS Name",Value:t.getAtt("LoadBalancer","DNSName"),Export:{Name:t.sub("${AWS::StackName}-alb-dns")}}})}function hn(e,n,r){let i=e.toLogicalId(n),s=r.taskDefinition.containerDefinitions?.[0],a=s?.name||s?.Name||n,c=s?.portMappings?.[0]?.containerPort||s?.PortMappings?.[0]?.ContainerPort||3000,u=(r.taskDefinition.containerDefinitions||[]).flatMap((y)=>(y.secrets||y.Secrets||[]).map((f)=>f.valueFrom||f.ValueFrom)).filter(Boolean);if(!e.hasResource("ECSCluster"))e.addResource("ECSCluster","AWS::ECS::Cluster",{ClusterName:t.sub("${AWS::StackName}-cluster"),Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-cluster")}]});if(e.addResource(`${i}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"],...u.length?{Policies:[{PolicyName:"read-task-secrets",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameters"],Resource:u},{Effect:"Allow",Action:"kms:Decrypt",Resource:"*"}]}}]}:{}}),e.addResource(`${i}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:t.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:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0"},...r.loadBalancer?.customDomain?.certificateArn?[{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0"}]:[]],SecurityGroupEgress:[{IpProtocol:"tcp",FromPort:c,ToPort:c,CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:t.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:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:c,ToPort:c,SourceSecurityGroupId:t.ref("ALBSecurityGroup")}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-app-sg")}]},{dependsOn:["VPC","ALBSecurityGroup"]});let d=(r.taskDefinition.containerDefinitions||[{name:n,image:t.sub(`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${n}:latest`),portMappings:[{containerPort:3000}]}]).map((y)=>({Name:y.Name||y.name,Image:y.Image||y.image,Essential:y.Essential??y.essential??!0,PortMappings:(y.PortMappings||y.portMappings||[]).map((f)=>({ContainerPort:f.ContainerPort??f.containerPort,Protocol:f.Protocol||f.protocol||"tcp"})),Environment:Array.isArray(y.Environment||y.environment)?(y.Environment||y.environment).map((f)=>({Name:f.Name||f.name,Value:f.Value??f.value})):Object.entries(y.Environment||y.environment||{}).map(([f,h])=>({Name:f,Value:h})),Secrets:(y.Secrets||y.secrets||[]).map((f)=>({Name:f.Name||f.name,ValueFrom:f.ValueFrom||f.valueFrom})),HealthCheck:y.HealthCheck||y.healthCheck,Command:y.Command||y.command,EntryPoint:y.EntryPoint||y.entryPoint,LogConfiguration:y.LogConfiguration||y.logConfiguration||{LogDriver:"awslogs",Options:{"awslogs-group":t.ref(`${i}LogGroup`),"awslogs-region":t.ref("AWS::Region"),"awslogs-stream-prefix":n}}}));e.addResource(`${i}TaskDefinition`,"AWS::ECS::TaskDefinition",{Family:t.sub(`\${AWS::StackName}-${n}`),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:r.taskDefinition.cpu,Memory:r.taskDefinition.memory,ExecutionRoleArn:t.getAtt(`${i}TaskExecutionRole`,"Arn"),TaskRoleArn:t.getAtt(`${i}TaskRole`,"Arn"),ContainerDefinitions:d},{dependsOn:[`${i}TaskExecutionRole`,`${i}TaskRole`,`${i}LogGroup`]}),e.addResource(`${i}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:t.sub(`/ecs/\${AWS::StackName}/${n}`),RetentionInDays:14});let m=r.service.healthCheck||{};e.addResource(`${i}TargetGroup`,"AWS::ElasticLoadBalancingV2::TargetGroup",{VpcId:t.ref("VPC"),Port:c,Protocol:"HTTP",TargetType:"ip",HealthCheckEnabled:!0,HealthCheckPath:m.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:m.interval||30,HealthCheckTimeoutSeconds:m.timeout||5,HealthyThresholdCount:m.healthyThreshold||2,UnhealthyThresholdCount:m.unhealthyThreshold||3,Matcher:{HttpCode:"200-399"},TargetGroupAttributes:[{Key:"deregistration_delay.timeout_seconds",Value:"30"}]},{dependsOn:"VPC"}),e.addResource(`${i}LoadBalancer`,"AWS::ElasticLoadBalancingV2::LoadBalancer",{Type:"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[t.ref("PublicSubnet1"),t.ref("PublicSubnet2")],SecurityGroups:[t.ref("ALBSecurityGroup")],LoadBalancerAttributes:[{Key:"routing.http.drop_invalid_header_fields.enabled",Value:"true"},{Key:"deletion_protection.enabled",Value:String(r.loadBalancer?.deletionProtection===!0)}],Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}-alb`)}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]});let p=r.loadBalancer?.customDomain?.certificateArn,g=r.loadBalancer?.originVerifyHeader;if(e.addResource(`${i}HttpListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:t.ref(`${i}LoadBalancer`),Port:80,Protocol:"HTTP",DefaultActions:p?[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]:g?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:t.ref(`${i}TargetGroup`)}]},{dependsOn:[`${i}LoadBalancer`,`${i}TargetGroup`]}),p)e.addResource(`${i}HttpsListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:t.ref(`${i}LoadBalancer`),Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:p}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06",DefaultActions:g?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:t.ref(`${i}TargetGroup`)}]},{dependsOn:[`${i}LoadBalancer`,`${i}TargetGroup`]});if(g){let y=p?`${i}HttpsListener`:`${i}HttpListener`;e.addResource(`${i}OriginVerifyRule`,"AWS::ElasticLoadBalancingV2::ListenerRule",{ListenerArn:t.ref(y),Priority:1,Conditions:[{Field:"http-header",HttpHeaderConfig:{HttpHeaderName:g.name,Values:[g.value]}}],Actions:[{Type:"forward",TargetGroupArn:t.ref(`${i}TargetGroup`)}]},{dependsOn:[y,`${i}TargetGroup`]})}if(e.addResource(`${i}Service`,"AWS::ECS::Service",{ServiceName:t.sub(`\${AWS::StackName}-${n}`),Cluster:t.ref("ECSCluster"),TaskDefinition:t.ref(`${i}TaskDefinition`),DesiredCount:r.service.desiredCount,LaunchType:"FARGATE",PlatformVersion:"LATEST",HealthCheckGracePeriodSeconds:60,DeploymentConfiguration:{MinimumHealthyPercent:100,MaximumPercent:200,DeploymentCircuitBreaker:{Enable:!0,Rollback:!0}},LoadBalancers:[{ContainerName:a,ContainerPort:c,TargetGroupArn:t.ref(`${i}TargetGroup`)}],NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"DISABLED",Subnets:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],SecurityGroups:[t.ref("AppSecurityGroup")]}}},{dependsOn:["ECSCluster",`${i}TaskDefinition`,g?`${i}OriginVerifyRule`:p?`${i}HttpsListener`:`${i}HttpListener`]}),r.service.autoScaling){let y=r.service.autoScaling;e.addResource(`${i}ScalableTarget`,"AWS::ApplicationAutoScaling::ScalableTarget",{MinCapacity:y.min,MaxCapacity:y.max,ResourceId:t.join("/",["service",t.ref("ECSCluster"),t.getAtt(`${i}Service`,"Name")]),RoleARN:t.sub("arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"),ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs"},{dependsOn:`${i}Service`}),e.addResource(`${i}ScalingPolicy`,"AWS::ApplicationAutoScaling::ScalingPolicy",{PolicyType:"TargetTrackingScaling",ScalingTargetId:t.ref(`${i}ScalableTarget`),TargetTrackingScalingPolicyConfiguration:{TargetValue:y.targetCPU||70,PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},ScaleInCooldown:60,ScaleOutCooldown:30}},{dependsOn:`${i}ScalableTarget`})}e.addOutputs({[`${i}ClusterName`]:{Description:"ECS cluster name",Value:t.ref("ECSCluster")},[`${i}ServiceName`]:{Description:"ECS service name",Value:t.getAtt(`${i}Service`,"Name")},[`${i}LoadBalancerDnsName`]:{Description:"ALB origin hostname",Value:t.getAtt(`${i}LoadBalancer`,"DNSName")},[`${i}LoadBalancerHostedZoneId`]:{Description:"ALB canonical hosted zone ID",Value:t.getAtt(`${i}LoadBalancer`,"CanonicalHostedZoneID")},[`${i}TargetGroupArn`]:{Description:"ECS target group ARN",Value:t.ref(`${i}TargetGroup`)}})}function Cn(e,n){if(n.postgres)Sn(e,"postgres",n.postgres);if(n.mysql)Sn(e,"mysql",n.mysql);if(n.dynamodb?.tables)n.dynamodb.tables.forEach((r)=>{vi(e,r)})}function Sn(e,n,r){if(!r)return;let i=n==="postgres"?"postgres":"mysql",s=e.toLogicalId(`${i}-db`);e.addResource("DBSubnetGroup","AWS::RDS::DBSubnetGroup",{DBSubnetGroupDescription:"Subnet group for RDS instance",SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-db-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),e.addResource("DBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for RDS instance",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:n==="postgres"?5432:3306,ToPort:n==="postgres"?5432:3306,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-db-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});let a=n==="postgres"?`postgres${r.version.split(".")[0]}`:`mysql${r.version.split(".")[0]}.${r.version.split(".")[1]||"0"}`;if(r.parameters&&Object.keys(r.parameters).length>0)e.addResource("DBParameterGroup","AWS::RDS::DBParameterGroup",{Description:`Parameter group for ${i}`,Family:a,Parameters:r.parameters,Tags:[{Key:"Name",Value:t.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:t.sub("${AWS::StackName}-db-secret")}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"});let c={Engine:i,EngineVersion:r.version,DBInstanceClass:r.instanceClass,AllocatedStorage:r.allocatedStorage.toString(),MaxAllocatedStorage:r.maxAllocatedStorage?.toString(),StorageType:"gp3",StorageEncrypted:!0,MultiAZ:r.multiAZ!==!1,DBSubnetGroupName:t.ref("DBSubnetGroup"),VPCSecurityGroups:[t.ref("DBSecurityGroup")],MasterUsername:t.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:username}}"),MasterUserPassword:t.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:password}}"),BackupRetentionPeriod:r.backupRetentionDays||7,PreferredBackupWindow:r.preferredBackupWindow||"03:00-04:00",PreferredMaintenanceWindow:r.preferredMaintenanceWindow||"sun:04:00-sun:05:00",EnablePerformanceInsights:r.enablePerformanceInsights!==!1,PerformanceInsightsRetentionPeriod:r.performanceInsightsRetention||7,DeletionProtection:r.deletionProtection!==!1,CopyTagsToSnapshot:!0,EnableCloudwatchLogsExports:n==="postgres"?["postgresql"]:["error","general","slowquery"],Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${i}-db`)}]};if(r.parameters&&Object.keys(r.parameters).length>0)c.DBParameterGroupName=t.ref("DBParameterGroup");e.addResource(s,"AWS::RDS::DBInstance",c,{dependsOn:["DBSubnetGroup","DBSecurityGroup","DBSecret"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),e.addResource("DBSecretAttachment","AWS::SecretsManager::SecretTargetAttachment",{SecretId:t.ref("DBSecret"),TargetId:t.ref(s),TargetType:"AWS::RDS::DBInstance"},{dependsOn:[s,"DBSecret"]}),e.addOutputs({DBEndpoint:{Description:"Database endpoint",Value:t.getAtt(s,"Endpoint.Address"),Export:{Name:t.sub("${AWS::StackName}-db-endpoint")}},DBPort:{Description:"Database port",Value:t.getAtt(s,"Endpoint.Port"),Export:{Name:t.sub("${AWS::StackName}-db-port")}},DBSecretArn:{Description:"ARN of the database credentials secret",Value:t.ref("DBSecret"),Export:{Name:t.sub("${AWS::StackName}-db-secret-arn")}}})}function vi(e,n){let r=e.toLogicalId(`${n.name}-table`),i={TableName:t.sub(`\${AWS::StackName}-${n.name}`),BillingMode:n.billingMode||"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:n.partitionKey,AttributeType:"S"}],KeySchema:[{AttributeName:n.partitionKey,KeyType:"HASH"}],Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n.name}`)}]};if(n.sortKey)i.AttributeDefinitions.push({AttributeName:n.sortKey,AttributeType:"S"}),i.KeySchema.push({AttributeName:n.sortKey,KeyType:"RANGE"});if(n.billingMode==="PROVISIONED")i.ProvisionedThroughput={ReadCapacityUnits:n.readCapacity||5,WriteCapacityUnits:n.writeCapacity||5};if(n.streamEnabled)i.StreamSpecification={StreamViewType:"NEW_AND_OLD_IMAGES"};if(n.pointInTimeRecovery)i.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(n.ttl?.enabled)i.TimeToLiveSpecification={Enabled:!0,AttributeName:n.ttl.attributeName};if(n.globalSecondaryIndexes&&n.globalSecondaryIndexes.length>0)i.GlobalSecondaryIndexes=n.globalSecondaryIndexes.map((s)=>{let a=new Set(i.AttributeDefinitions.map((u)=>u.AttributeName));if(!a.has(s.partitionKey))i.AttributeDefinitions.push({AttributeName:s.partitionKey,AttributeType:"S"});if(s.sortKey&&!a.has(s.sortKey))i.AttributeDefinitions.push({AttributeName:s.sortKey,AttributeType:"S"});let c={IndexName:s.name,KeySchema:[{AttributeName:s.partitionKey,KeyType:"HASH"}],Projection:{ProjectionType:s.projectionType||"ALL"}};if(s.sortKey)c.KeySchema.push({AttributeName:s.sortKey,KeyType:"RANGE"});if(s.projectionType==="INCLUDE"&&s.nonKeyAttributes)c.Projection.NonKeyAttributes=s.nonKeyAttributes;if(n.billingMode==="PROVISIONED")c.ProvisionedThroughput={ReadCapacityUnits:n.readCapacity||5,WriteCapacityUnits:n.writeCapacity||5};return c});if(e.addResource(r,"AWS::DynamoDB::Table",i,{deletionPolicy:"Retain"}),e.addOutputs({[`${r}Name`]:{Description:`${n.name} table name`,Value:t.ref(r),Export:{Name:t.sub(`\${AWS::StackName}-${n.name}-table`)}},[`${r}Arn`]:{Description:`${n.name} table ARN`,Value:t.getAtt(r,"Arn"),Export:{Name:t.sub(`\${AWS::StackName}-${n.name}-table-arn`)}}}),n.streamEnabled)e.addOutputs({[`${r}StreamArn`]:{Description:`${n.name} stream ARN`,Value:t.getAtt(r,"StreamArn"),Export:{Name:t.sub(`\${AWS::StackName}-${n.name}-stream-arn`)}}})}function vn(e,n){for(let[r,i]of Object.entries(n))i.forEach((s)=>{Ti(e,s,r)})}function Ti(e,n,r){let i=e.toLogicalId(`${r}-${n.name}-function`),s=`${i}Role`;e.addResource(s,"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:[...Pi(n.events||[])]}}],Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n.name}-role`)}]});let a={FunctionName:t.sub(`\${AWS::StackName}-${n.name}`),Runtime:n.runtime,Handler:n.handler,Role:t.getAtt(s,"Arn"),MemorySize:n.memory,Timeout:n.timeout,Code:{ZipFile:`exports.handler = async (event) => {
|
|
2449
2449
|
console.log('Event:', JSON.stringify(event, null, 2));
|
|
2450
2450
|
return { statusCode: 200, body: 'Function not yet implemented' };
|
|
2451
|
-
};`},Environment:n.environment?{Variables:n.environment}:void 0,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n.name}`)}]};if(r!=="edge")a.VpcConfig={SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],SecurityGroupIds:[t.ref("AppSecurityGroup")]};if(e.addResource(i,"AWS::Lambda::Function",a,{dependsOn:s}),e.addResource(`${i}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:t.sub(`/aws/lambda/\${AWS::StackName}-${n.name}`),RetentionInDays:14}),n.events)n.events.forEach((c,u)=>{
|
|
2451
|
+
};`},Environment:n.environment?{Variables:n.environment}:void 0,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n.name}`)}]};if(r!=="edge")a.VpcConfig={SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],SecurityGroupIds:[t.ref("AppSecurityGroup")]};if(e.addResource(i,"AWS::Lambda::Function",a,{dependsOn:s}),e.addResource(`${i}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:t.sub(`/aws/lambda/\${AWS::StackName}-${n.name}`),RetentionInDays:14}),n.events)n.events.forEach((c,u)=>{Ri(e,i,c,u)});e.addOutputs({[`${i}Arn`]:{Description:`${n.name} function ARN`,Value:t.getAtt(i,"Arn"),Export:{Name:t.sub(`\${AWS::StackName}-${n.name}-function-arn`)}}})}function Ri(e,n,r,i){let s=`${n}EventSource${i}`;switch(r.type){case"http":break;case"s3":if(r.bucket){let a=e.toLogicalId(`${r.bucket}-bucket`);e.addResource(`${s}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(n),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:Pn.s3Bucket(t.ref(a))},{dependsOn:[n,a]})}break;case"sqs":if(r.queueName){let a=e.toLogicalId(`${r.queueName}-queue`);e.addResource(s,"AWS::Lambda::EventSourceMapping",{EventSourceArn:t.getAtt(a,"Arn"),FunctionName:t.ref(n),BatchSize:r.batchSize||10},{dependsOn:[n,a]})}break;case"kinesis":if(r.streamName){let a=e.toLogicalId(`${r.streamName}-stream`);e.addResource(s,"AWS::Lambda::EventSourceMapping",{EventSourceArn:t.getAtt(a,"Arn"),FunctionName:t.ref(n),BatchSize:r.batchSize||100,StartingPosition:r.startingPosition||"LATEST",ParallelizationFactor:r.parallelizationFactor||1},{dependsOn:[n,a]})}break;case"dynamodb-stream":if(r.tableName){let a=e.toLogicalId(`${r.tableName}-table`);e.addResource(s,"AWS::Lambda::EventSourceMapping",{EventSourceArn:t.getAtt(a,"StreamArn"),FunctionName:t.ref(n),BatchSize:r.batchSize||100,StartingPosition:r.startingPosition||"LATEST"},{dependsOn:[n,a]})}break;case"schedule":if(r.expression)e.addResource(`${s}Rule`,"AWS::Events::Rule",{ScheduleExpression:r.expression,State:"ENABLED",Targets:[{Arn:t.getAtt(n,"Arn"),Id:`${n}Target`}]},{dependsOn:n}),e.addResource(`${s}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(n),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.getAtt(`${s}Rule`,"Arn")},{dependsOn:[n,`${s}Rule`]});break}}function Pi(e){let n=[];if(!e)return n;if(e.forEach((r)=>{switch(r.type){case"s3":n.push({Effect:"Allow",Action:["s3:GetObject","s3:GetObjectVersion"],Resource:r.bucket?`arn:aws:s3:::${r.bucket}/*`:"arn:aws:s3:::*/*"});break;case"sqs":n.push({Effect:"Allow",Action:["sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes"],Resource:r.queueName?Pn.sqs(r.queueName):"arn:aws:sqs:*:*:*"});break;case"kinesis":n.push({Effect:"Allow",Action:["kinesis:GetRecords","kinesis:GetShardIterator","kinesis:DescribeStream","kinesis:ListStreams"],Resource:r.streamName?Pn.kinesis(r.streamName):"arn:aws:kinesis:*:*:stream/*"});break;case"dynamodb-stream":n.push({Effect:"Allow",Action:["dynamodb:GetRecords","dynamodb:GetShardIterator","dynamodb:DescribeStream","dynamodb:ListStreams"],Resource:r.tableName?t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${r.tableName}/stream/*`):"arn:aws:dynamodb:*:*:table/*/stream/*"});break}}),n.length===0)n.push({Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:*"});return n}function Tn(e,n){if(n.topics)n.topics.forEach((r)=>{Ei(e,r)})}function Ei(e,n){let r=e.toLogicalId(`${n.name}-topic`);if(e.addResource(r,"AWS::SNS::Topic",{TopicName:t.sub(`\${AWS::StackName}-${n.name}`),DisplayName:n.displayName||n.name,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n.name}`)}]}),e.addResource(`${r}Policy`,"AWS::SNS::TopicPolicy",{Topics:[t.ref(r)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["events.amazonaws.com","cloudwatch.amazonaws.com","s3.amazonaws.com"]},Action:"sns:Publish",Resource:t.ref(r)},{Effect:"Allow",Principal:{AWS:t.sub("arn:aws:iam::${AWS::AccountId}:root")},Action:["sns:Subscribe","sns:Publish","sns:Receive"],Resource:t.ref(r)}]}},{dependsOn:r}),n.subscriptions)n.subscriptions.forEach((i,s)=>{let a=`${r}Subscription${s+1}`,c={Protocol:i.protocol,TopicArn:t.ref(r),Endpoint:i.endpoint};if(i.filterPolicy)c.FilterPolicy=i.filterPolicy;if(i.protocol==="sqs"){let u=e.toLogicalId(`${i.endpoint}-queue`);c.Endpoint=t.getAtt(u,"Arn")}if(i.protocol==="lambda"){let u=e.toLogicalId(i.endpoint);c.Endpoint=t.getAtt(u,"Arn"),e.addResource(`${a}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(u),Action:"lambda:InvokeFunction",Principal:"sns.amazonaws.com",SourceArn:t.ref(r)},{dependsOn:[u,r]})}e.addResource(a,"AWS::SNS::Subscription",c,{dependsOn:r})});e.addOutputs({[`${r}Arn`]:{Description:`${n.name} topic ARN`,Value:t.ref(r),Export:{Name:t.sub(`\${AWS::StackName}-${n.name}-topic-arn`)}}})}function En(e,n){if(n.alarms&&n.alarms.length>0)e.addResource("AlarmTopic","AWS::SNS::Topic",{TopicName:t.sub("${AWS::StackName}-alarms"),DisplayName:"CloudWatch Alarms",Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-alarms")}]}),n.alarms.forEach((r,i)=>{wi(e,r,i)});if(n.dashboard)Ii(e,n.dashboard);if(n.logs?.groups)n.logs.groups.forEach((r)=>{Di(e,r,n.logs?.retention)})}function wi(e,n,r){let i=e.toLogicalId(`alarm-${n.name||n.metric}-${r}`),s={AlarmName:n.name||t.sub(`\${AWS::StackName}-${n.metric}`),AlarmDescription:`Alarm for ${n.metric}`,MetricName:n.metric,Namespace:n.namespace||Tt(n.metric,n.service),Statistic:n.statistic||"Average",Period:n.period||300,EvaluationPeriods:n.evaluationPeriods||1,Threshold:n.threshold,ComparisonOperator:n.comparisonOperator||"GreaterThanThreshold",TreatMissingData:n.treatMissingData||"notBreaching",AlarmActions:[t.ref("AlarmTopic")],OKActions:[t.ref("AlarmTopic")]};if(n.dimensions)s.Dimensions=Object.entries(n.dimensions).map(([a,c])=>({Name:a,Value:c}));else if(n.service)s.Dimensions=Ni(n.service);e.addResource(i,"AWS::CloudWatch::Alarm",s,{dependsOn:"AlarmTopic"})}function Ii(e,n){if(!n)return;let r=[],i=0,s=0;n.widgets?.forEach((a)=>{let c=a.width||12,u=a.height||6;if(a.type==="metric"&&a.metrics){let d=a.metrics.map((m)=>{if(typeof m==="string")return[Tt(m),m];else return[Tt(m.metric,m.service),m.metric]});r.push({type:"metric",x:i,y:s,width:c,height:u,properties:{metrics:d,period:300,stat:"Average",region:t.ref("AWS::Region"),title:a.metrics.length>1?"Multiple Metrics":typeof a.metrics[0]==="string"?a.metrics[0]:a.metrics[0].metric}})}else if(a.type==="log"&&a.logGroup)r.push({type:"log",x:i,y:s,width:c,height:u,properties:{query:`SOURCE '${a.logGroup}'
|
|
2452
2452
|
| fields @timestamp, @message
|
|
2453
2453
|
| sort @timestamp desc
|
|
2454
|
-
| limit 20`,region:t.ref("AWS::Region"),title:`Logs: ${a.logGroup}`}});else if(a.type==="text"&&a.text)r.push({type:"text",x:i,y:s,width:c,height:u,properties:{markdown:a.text}});if(i+=c,i>=24)i=0,s+=u}),e.addResource("CloudWatchDashboard","AWS::CloudWatch::Dashboard",{DashboardName:t.sub(`\${AWS::StackName}-${n.name}`),DashboardBody:JSON.stringify({widgets:r})}),e.addOutputs({DashboardURL:{Description:"CloudWatch Dashboard URL",Value:t.sub("https://console.aws.amazon.com/cloudwatch/home?region=${AWS::Region}#dashboards:name=${CloudWatchDashboard}")}})}function di(e,n,r){let i=e.toLogicalId(`${n}-log-group`);e.addResource(i,"AWS::Logs::LogGroup",{LogGroupName:t.sub(`/aws/\${AWS::StackName}/${n}`),RetentionInDays:r||14,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}`)}]})}function At(e,n){if(n)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"}[n.toLowerCase()]||"AWS/CloudWatch";let r=e.toLowerCase();if(r.includes("cpu")||r.includes("memory")||r.includes("network"))return"AWS/EC2";if(r.includes("lambda")||r.includes("invocation")||r.includes("duration"))return"AWS/Lambda";if(r.includes("request")||r.includes("latency")||r.includes("target"))return"AWS/ApplicationELB";if(r.includes("database")||r.includes("connection"))return"AWS/RDS";if(r.includes("read")||r.includes("write")||r.includes("consumed"))return"AWS/DynamoDB";return"AWS/CloudWatch"}function mi(e){return{ec2:[{Name:"InstanceId",Value:t.ref("EC2Instance")}],ecs:[{Name:"ClusterName",Value:t.ref("ECSCluster")},{Name:"ServiceName",Value:t.getAtt("ECSService","Name")}],lambda:[{Name:"FunctionName",Value:t.ref("LambdaFunction")}],rds:[{Name:"DBInstanceIdentifier",Value:t.ref("Database")}],dynamodb:[{Name:"TableName",Value:t.ref("DynamoDBTable")}],alb:[{Name:"LoadBalancer",Value:t.getAtt("LoadBalancer","LoadBalancerFullName")}],apigateway:[{Name:"ApiName",Value:t.ref("HttpApi")}]}[e.toLowerCase()]||[]}function Cn(e,n){if(!n.vpc)return;let{cidr:r="10.0.0.0/16",availabilityZones:i=2,natGateways:s=1,enableDnsHostnames:a=!0,enableDnsSupport:c=!0}=n.vpc;e.addResource("VPC","AWS::EC2::VPC",{CidrBlock:r,EnableDnsHostnames:a,EnableDnsSupport:c,Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-vpc")}]}),e.addResource("InternetGateway","AWS::EC2::InternetGateway",{Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-igw")}]}),e.addResource("VPCGatewayAttachment","AWS::EC2::VPCGatewayAttachment",{VpcId:t.ref("VPC"),InternetGatewayId:t.ref("InternetGateway")},{dependsOn:["VPC","InternetGateway"]});let u=[];for(let g=0;g<i;g++){let y=`PublicSubnet${g+1}`;u.push(y),e.addResource(y,"AWS::EC2::Subnet",{VpcId:t.ref("VPC"),CidrBlock:t.select(g,t.cidr(t.getAtt("VPC","CidrBlock"),i*2,8)),AvailabilityZone:t.select(g,t.getAZs()),MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-public-${g+1}`)},{Key:"Type",Value:"public"}]},{dependsOn:"VPC"})}let d=[];for(let g=0;g<i;g++){let y=`PrivateSubnet${g+1}`;d.push(y),e.addResource(y,"AWS::EC2::Subnet",{VpcId:t.ref("VPC"),CidrBlock:t.select(g+i,t.cidr(t.getAtt("VPC","CidrBlock"),i*2,8)),AvailabilityZone:t.select(g,t.getAZs()),MapPublicIpOnLaunch:!1,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-private-${g+1}`)},{Key:"Type",Value:"private"}]},{dependsOn:"VPC"})}let m=[];for(let g=0;g<s;g++){let y=`NatEIP${g+1}`;m.push(y),e.addResource(y,"AWS::EC2::EIP",{Domain:"vpc",Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-nat-eip-${g+1}`)}]},{dependsOn:"VPCGatewayAttachment"})}let p=[];for(let g=0;g<s;g++){let y=`NatGateway${g+1}`;p.push(y);let f=g%i;e.addResource(y,"AWS::EC2::NatGateway",{AllocationId:t.getAtt(m[g],"AllocationId"),SubnetId:t.ref(u[f]),Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-nat-${g+1}`)}]},{dependsOn:[m[g],u[f]]})}e.addResource("PublicRouteTable","AWS::EC2::RouteTable",{VpcId:t.ref("VPC"),Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-public-rt")}]},{dependsOn:"VPC"}),e.addResource("PublicRoute","AWS::EC2::Route",{RouteTableId:t.ref("PublicRouteTable"),DestinationCidrBlock:"0.0.0.0/0",GatewayId:t.ref("InternetGateway")},{dependsOn:["PublicRouteTable","VPCGatewayAttachment"]}),u.forEach((g,y)=>{e.addResource(`PublicSubnetRouteTableAssociation${y+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:t.ref(g),RouteTableId:t.ref("PublicRouteTable")},{dependsOn:[g,"PublicRouteTable"]})}),d.forEach((g,y)=>{let f=`PrivateRouteTable${y+1}`,h=y%s;e.addResource(f,"AWS::EC2::RouteTable",{VpcId:t.ref("VPC"),Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-private-rt-${y+1}`)}]},{dependsOn:"VPC"}),e.addResource(`PrivateRoute${y+1}`,"AWS::EC2::Route",{RouteTableId:t.ref(f),DestinationCidrBlock:"0.0.0.0/0",NatGatewayId:t.ref(p[h])},{dependsOn:[f,p[h]]}),e.addResource(`PrivateSubnetRouteTableAssociation${y+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:t.ref(g),RouteTableId:t.ref(f)},{dependsOn:[g,f]})}),e.addResource("S3VPCEndpoint","AWS::EC2::VPCEndpoint",{VpcId:t.ref("VPC"),ServiceName:t.sub("com.amazonaws.${AWS::Region}.s3"),VpcEndpointType:"Gateway",RouteTableIds:[t.ref("PublicRouteTable"),...Array.from({length:i},(g,y)=>t.ref(`PrivateRouteTable${y+1}`))]},{dependsOn:"VPC"}),e.addResource("NetworkAcl","AWS::EC2::NetworkAcl",{VpcId:t.ref("VPC"),Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-nacl")}]},{dependsOn:"VPC"}),e.addResource("NetworkAclEntryInbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:t.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),e.addResource("NetworkAclEntryOutbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:t.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:t.ref("VPC"),Export:{Name:t.sub("${AWS::StackName}-VPC")}},PublicSubnets:{Description:"Public subnet IDs",Value:t.join(",",u.map((g)=>t.ref(g))),Export:{Name:t.sub("${AWS::StackName}-PublicSubnets")}},PrivateSubnets:{Description:"Private subnet IDs",Value:t.join(",",d.map((g)=>t.ref(g))),Export:{Name:t.sub("${AWS::StackName}-PrivateSubnets")}}})}function vn(e,n){for(let[r,i]of Object.entries(n))pi(e,r,i)}function pi(e,n,r){let i=e.toLogicalId(`${n}-queue`),s=r.fifo||!1,a;if(r.deadLetterQueue){let u=`${i}DLQ`;e.addResource(u,"AWS::SQS::Queue",{QueueName:s?t.sub(`\${AWS::StackName}-${n}-dlq.fifo`):t.sub(`\${AWS::StackName}-${n}-dlq`),FifoQueue:s,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}-dlq`)}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),a=t.getAtt(u,"Arn")}let c={QueueName:s?t.sub(`\${AWS::StackName}-${n}.fifo`):t.sub(`\${AWS::StackName}-${n}`),FifoQueue:s,VisibilityTimeout:r.visibilityTimeout||30,MessageRetentionPeriod:r.messageRetentionPeriod||345600,ReceiveMessageWaitTimeSeconds:r.receiveMessageWaitTime||0,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}`)}]};if(s&&r.contentBasedDeduplication)c.ContentBasedDeduplication=!0;if(r.deadLetterQueue&&a)c.RedrivePolicy={deadLetterTargetArn:a,maxReceiveCount:r.maxReceiveCount||3};if(e.addResource(i,"AWS::SQS::Queue",c,{dependsOn:r.deadLetterQueue?`${i}DLQ`:void 0,deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),e.addResource(`${i}Policy`,"AWS::SQS::QueuePolicy",{Queues:[t.ref(i)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","events.amazonaws.com","sns.amazonaws.com"]},Action:"sqs:SendMessage",Resource:t.getAtt(i,"Arn"),Condition:{ArnEquals:{"aws:SourceArn":t.sub("arn:aws:*:${AWS::Region}:${AWS::AccountId}:*")}}}]}},{dependsOn:i}),e.addOutputs({[`${i}Url`]:{Description:`${n} queue URL`,Value:t.ref(i),Export:{Name:t.sub(`\${AWS::StackName}-${n}-queue-url`)}},[`${i}Arn`]:{Description:`${n} queue ARN`,Value:t.getAtt(i,"Arn"),Export:{Name:t.sub(`\${AWS::StackName}-${n}-queue-arn`)}}}),r.deadLetterQueue)e.addOutputs({[`${i}DLQUrl`]:{Description:`${n} dead letter queue URL`,Value:t.ref(`${i}DLQ`),Export:{Name:t.sub(`\${AWS::StackName}-${n}-dlq-url`)}}})}function Tn(e,n){if(n.certificate)gi(e,n.certificate);if(n.waf?.enabled)yi(e,n.waf);if(n.securityGroups)for(let[r,i]of Object.entries(n.securityGroups))fi(e,r,i)}function gi(e,n){if(!n)return;let r=[n.domain];if(n.subdomains)r.push(...n.subdomains);e.addResource("Certificate","AWS::CertificateManager::Certificate",{DomainName:n.domain,SubjectAlternativeNames:n.subdomains,ValidationMethod:n.validationMethod||"DNS",DomainValidationOptions:r.map((i)=>({DomainName:i,HostedZoneId:t.ref("HostedZone")})),Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-certificate")}]}),e.addOutputs({CertificateArn:{Description:"ACM Certificate ARN",Value:t.ref("Certificate"),Export:{Name:t.sub("${AWS::StackName}-certificate-arn")}}})}function yi(e,n){if(!n)return;let r=[],i=n.rules||["rateLimit","sqlInjection","xss"];if(i.includes("rateLimit"))r.push({Name:"RateLimitRule",Priority:1,Statement:{RateBasedStatement:{Limit:n.rateLimit||2000,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"RateLimitRule"}});let s=r.length+1;if(i.includes("sqlInjection"))r.push({Name:"AWSManagedRulesSQLi",Priority:s++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesSQLiRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesSQLi"}});if(i.includes("xss"))r.push({Name:"AWSManagedRulesXSS",Priority:s++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesXSS"}});if(i.includes("knownBadInputs"))r.push({Name:"AWSManagedRulesKnownBadInputs",Priority:s++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesKnownBadInputs"}});if(i.includes("coreRuleSet"))r.push({Name:"AWSManagedRulesCoreRuleSet",Priority:s++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesCommonRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesCoreRuleSet"}});if(i.includes("linuxRuleSet"))r.push({Name:"AWSManagedRulesLinuxRuleSet",Priority:s++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesLinuxRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesLinuxRuleSet"}});if(i.includes("apiProtection"))r.push({Name:"AWSManagedRulesAPIProtection",Priority:s++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesAmazonIpReputationList"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesAPIProtection"}});if(i.includes("geoBlock"))r.push({Name:"GeoBlockRule",Priority:s++,Statement:{GeoMatchStatement:{CountryCodes:["CN","RU"]}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"GeoBlockRule"}});if(i.includes("connectionLimit"))r.push({Name:"ConnectionLimitRule",Priority:s++,Statement:{RateBasedStatement:{Limit:100,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"ConnectionLimitRule"}});if(e.addResource("WebACL","AWS::WAFv2::WebACL",{Name:t.sub("${AWS::StackName}-waf"),Scope:n.scope||"REGIONAL",DefaultAction:{Allow:{}},Rules:r,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:t.sub("${AWS::StackName}-waf")},Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-waf")}]}),e.hasResource("LoadBalancer"))e.addResource("WebACLAssociation","AWS::WAFv2::WebACLAssociation",{ResourceArn:t.ref("LoadBalancer"),WebACLArn:t.getAtt("WebACL","Arn")},{dependsOn:["WebACL","LoadBalancer"]});e.addOutputs({WebACLId:{Description:"WAF Web ACL ID",Value:t.ref("WebACL"),Export:{Name:t.sub("${AWS::StackName}-waf-id")}},WebACLArn:{Description:"WAF Web ACL ARN",Value:t.getAtt("WebACL","Arn"),Export:{Name:t.sub("${AWS::StackName}-waf-arn")}}})}function fi(e,n,r){if(!r)return;let i=e.toLogicalId(`${n}-security-group`),s=r.ingress?.map((c)=>({IpProtocol:c.protocol,FromPort:c.port,ToPort:c.port,CidrIp:c.cidr,SourceSecurityGroupId:c.source?t.ref(c.source):void 0}))||[],a=r.egress?.map((c)=>({IpProtocol:c.protocol,FromPort:c.port,ToPort:c.port,CidrIp:c.cidr||"0.0.0.0/0"}))||[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}];e.addResource(i,"AWS::EC2::SecurityGroup",{GroupDescription:`Security group for ${n}`,VpcId:t.ref("VPC"),SecurityGroupIngress:s,SecurityGroupEgress:a,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}-sg`)}]},{dependsOn:"VPC"}),e.addOutputs({[`${i}Id`]:{Description:`${n} security group ID`,Value:t.ref(i),Export:{Name:t.sub(`\${AWS::StackName}-${n}-sg-id`)}}})}function En(e,n){for(let[r,i]of Object.entries(n)){if(i.type==="efs"){bi(e,r,i);continue}hi(e,r,i)}}function hi(e,n,r){let i=e.toLogicalId(`${n}-bucket`),s={BucketName:t.sub(`\${AWS::StackName}-${n}`),Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}`)}]};if(r.versioning)s.VersioningConfiguration={Status:"Enabled"};if(r.encryption)s.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(!r.public)s.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(r.website)s.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"index.html"};if(r.cors&&r.cors.length>0)s.CorsConfiguration={CorsRules:r.cors.map((a)=>({AllowedOrigins:a.allowedOrigins,AllowedMethods:a.allowedMethods,AllowedHeaders:a.allowedHeaders||["*"],MaxAge:a.maxAge||3600}))};if(r.lifecycleRules&&r.lifecycleRules.length>0)s.LifecycleConfiguration={Rules:r.lifecycleRules.map((a)=>({Id:a.id,Status:a.enabled?"Enabled":"Disabled",ExpirationInDays:a.expirationDays,Transitions:a.transitions?.map((c)=>({TransitionInDays:c.days,StorageClass:c.storageClass}))}))};if(r.intelligentTiering)s.IntelligentTieringConfigurations=[{Id:"EntireBucket",Status:"Enabled",Tierings:[{AccessTier:"ARCHIVE_ACCESS",Days:90},{AccessTier:"DEEP_ARCHIVE_ACCESS",Days:180}]}];if(e.addResource(i,"AWS::S3::Bucket",s,{deletionPolicy:r.versioning?"Retain":"Delete"}),r.public)e.addResource(`${i}Policy`,"AWS::S3::BucketPolicy",{Bucket:t.ref(i),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:"s3:GetObject",Resource:t.join("",[In.s3Bucket(t.ref(i)),"/*"])}]}},{dependsOn:i});if(e.addOutputs({[`${i}Name`]:{Description:`${n} bucket name`,Value:t.ref(i),Export:{Name:t.sub(`\${AWS::StackName}-${n}-bucket`)}},[`${i}Arn`]:{Description:`${n} bucket ARN`,Value:t.getAtt(i,"Arn"),Export:{Name:t.sub(`\${AWS::StackName}-${n}-bucket-arn`)}}}),r.website)e.addOutputs({[`${i}WebsiteURL`]:{Description:`${n} website URL`,Value:t.getAtt(i,"WebsiteURL")}})}function bi(e,n,r){let i=e.toLogicalId(`${n}-efs`),s={Encrypted:r.encryption!==!1,PerformanceMode:r.performanceMode||"generalPurpose",ThroughputMode:r.throughputMode||"bursting",FileSystemTags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}`)}]};if(r.lifecyclePolicy){if(s.LifecyclePolicies=[],r.lifecyclePolicy.transitionToIA)s.LifecyclePolicies.push({TransitionToIA:`AFTER_${r.lifecyclePolicy.transitionToIA}_DAYS`});if(r.lifecyclePolicy.transitionToPrimaryStorageClass)s.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"})}e.addResource(i,"AWS::EFS::FileSystem",s,{deletionPolicy:"Retain"});let a=2;for(let c=0;c<a;c++)e.addResource(`${i}MountTarget${c+1}`,"AWS::EFS::MountTarget",{FileSystemId:t.ref(i),SubnetId:t.ref(`PrivateSubnet${c+1}`),SecurityGroups:[t.ref("EFSSecurityGroup")]},{dependsOn:[i,`PrivateSubnet${c+1}`]});e.addResource("EFSSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for EFS mount targets",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-efs-sg")}]},{dependsOn:"VPC"}),e.addOutputs({[`${i}Id`]:{Description:`${n} EFS file system ID`,Value:t.ref(i),Export:{Name:t.sub(`\${AWS::StackName}-${n}-efs`)}}})}class fl{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:t.equals(t.ref("Environment"),"production"),HasDomain:t.not([t.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:t.ref("AWS::StackName"),Export:{Name:t.sub("${AWS::StackName}-Name")}},Region:{Description:"AWS Region",Value:t.ref("AWS::Region"),Export:{Name:t.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,n,r,i){let s={Type:n,Properties:r};if(i?.dependsOn)s.DependsOn=i.dependsOn,this.trackDependency(e,i.dependsOn);if(i?.condition)s.Condition=i.condition;if(i?.deletionPolicy)s.DeletionPolicy=i.deletionPolicy;if(i?.updateReplacePolicy)s.UpdateReplacePolicy=i.updateReplacePolicy;this.template.Resources[e]=s}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,n){if(!this.resourceDependencies.has(e))this.resourceDependencies.set(e,new Set);(Array.isArray(n)?n:[n]).forEach((i)=>this.resourceDependencies.get(e).add(i))}resolveDependencies(){let e=new Set,n=new Set,r=(i)=>{if(n.has(i))throw Error(`Circular dependency detected involving resource: ${i}`);if(e.has(i))return!0;e.add(i),n.add(i);let s=this.resourceDependencies.get(i);if(s)for(let a of s)r(a);return n.delete(i),!0};for(let i of this.resourceDependencies.keys())r(i)}toLogicalId(e){return e.split(/[-_\s]/).map((n)=>n.charAt(0).toUpperCase()+n.slice(1).toLowerCase()).join("")}addNetworkResources(e){Cn(this,e)}addStorageResources(e){En(this,e)}addComputeResources(e){gn(this,e)}addDatabaseResources(e){fn(this,e)}addFunctionResources(e){hn(this,e)}addCacheResources(e){dn(this,e)}addQueueResources(e){vn(this,e)}addMessagingResources(e){bn(this,e)}addCDNResources(e){mn(this,e)}addApiGatewayResources(e){un(this,e)}addMonitoringResources(e){Sn(this,e)}addSecurityResources(e){Tn(this,e)}}function Pa(e){return new fl(e).build()}function Om(e){let{name:n,slug:r,domain:i,subdomain:s}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:s&&i?`${s}.${i}`:i}},infrastructure:{storage:{assets:{public:!0,versioning:!1,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"],allowedHeaders:["*"],maxAge:3600}]}},cdn:{enabled:!0,customDomain:i?{domain:s&&i?`${s}.${i}`:i,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 $m(e){let{name:n,slug:r,domain:i,instanceType:s="t3.small",minInstances:a=2,maxInstances:c=10}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:i}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:s,ami:"ubuntu-22.04",keyPair:`${r}-key`,autoScaling:{min:a,max:c,desired:a,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:i?{domain:i,subdomains:[`*.${i}`],validationMethod:"DNS"}:void 0}}}}function Lm(e){let{name:n,slug:r,domain:i,taskCpu:s="256",taskMemory:a="512",desiredCount:c=2}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:0}},compute:{fargate:{taskDefinition:{cpu:s,memory:a,containerDefinitions:[{name:"app",image:`${r}-app:latest`,portMappings:[{containerPort:3000}],environment:[],secrets:[]}]},service:{desiredCount:c,healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},autoScaling:{min:c,max:c*5,targetCPU:70,targetMemory:80}},loadBalancer:{type:"application"}}},databases:{dynamodb:{tables:{[`${r}-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:`${r}-queue`}]}},security:{certificate:i?{domain:i,subdomains:[`*.${i}`],validationMethod:"DNS"}:void 0}}}}function Mm(e){let{name:n,slug:r,entry:i,domain:s,runtime:a="nodejs20.x",memory:c=1024,build:u,deploy:d,assets:m,queues:p=!0,scheduler:g="on",region:y="us-east-1"}=e;return{project:{name:n,slug:r,region:y},mode:"serverless",environments:{production:{type:"production",domain:s,app:{kind:"node",runtime:a,entry:i,memory:c,build:u,deploy:d,assets:m,queues:p,scheduler:g,domain:s}}}}}function Da(e){let n=e.database!==!1,r=e.cache!==!1,i=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:t.ref("AWS::Region")},...n?[{name:"DB_HOST",value:t.getAtt("PostgresDb","Endpoint.Address")},{name:"DB_PORT",value:t.getAtt("PostgresDb","Endpoint.Port")}]:[],...r?[{name:"REDIS_HOST",value:t.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address")},{name:"REDIS_PORT",value:t.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port")},{name:"REDIS_TLS",value:"true"}]:[],...i?[{name:"QUEUE_URL",value:t.ref("JobsQueue")}]:[],{name:"MAIL_TRANSPORT",value:"ses"}],secrets:n?[{name:"DB_USERNAME",valueFrom:t.sub("${DBSecret}:username::")},{name:"DB_PASSWORD",valueFrom:t.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}}:{}}}},...n?{databases:{postgres:{engine:"postgres",version:"16",instanceClass:"db.t4g.micro",allocatedStorage:20,maxAllocatedStorage:100,multiAZ:!1,backupRetentionDays:7,deletionProtection:!0}}}:{},...r?{cache:{redis:{nodeType:"cache.t4g.micro",numCacheNodes:2,engine:"redis",engineVersion:"7.1",automaticFailoverEnabled:!0,snapshotRetentionLimit:5}}}:{},...i?{queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0,maxReceiveCount:3,receiveMessageWaitTime:20}}}:{}}}}function Um(e){let{name:n,slug:r,domain:i,apiSubdomain:s="api"}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:i}},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:i,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:`${r}-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:`${s}.${i}`,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:i,subdomains:[`*.${i}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss"]}}}}}function Bm(e){let{name:n,slug:r,domain:i}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i}},infrastructure:{apiGateway:{type:"HTTP",cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"],allowHeaders:["Content-Type","Authorization"],maxAge:3600},customDomain:i?{domain:i,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:{[`${r}-users`]:{partitionKey:{name:"userId",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"EmailIndex",partitionKey:{name:"email",type:"S"},projection:"ALL"}]},[`${r}-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:i?{domain:i,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 Fm(e){let{name:n,slug:r,domain:i,instanceType:s="t3.small"}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:i}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:s,ami:"ubuntu-22.04",keyPair:`${r}-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:i,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,origins:[{type:"alb",pathPattern:"/wp-content/*"}]},security:{certificate:{domain:i,subdomains:[`www.${i}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","wordpressRules"]}}}}}function jm(e){let{name:n,slug:r,domain:i,apiDomain:s}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i}},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:i,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},...s?{api:{runtime:"nodejs20.x",handler:"dist/api/index.handler",memory:1024,timeout:30,events:[{type:"http",path:"/{proxy+}",method:"ANY"}]}}:{}},apiGateway:s?{type:"HTTP",customDomain:{domain:s,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:[i],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:i,subdomains:s?[s]:[],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","geoBlock"]}}}}}function Vm(e){let{name:n,slug:r,domain:i,services:s}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:3,natGateways:2}},compute:{services:s.map((a)=>({name:a.name,type:"fargate",taskDefinition:{cpu:a.cpu||"256",memory:a.memory||"512",containerDefinitions:[{name:a.name,image:`${r}-${a.name}:latest`,portMappings:[{containerPort:a.port}],healthCheck:{command:["CMD-SHELL",`curl -f http://localhost:${a.port}/health || exit 1`],interval:30,timeout:5,retries:3}}]},service:{desiredCount:a.desiredCount||2,serviceDiscovery:{enabled:!0,namespace:`${r}.local`},autoScaling:{min:2,max:10,targetCPU:70}}}))},apiGateway:{type:"HTTP",customDomain:{domain:i,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"]},routes:s.map((a)=>({path:`/${a.name}/{proxy+}`,integration:{type:"vpc-link",service:a.name}}))},databases:{dynamodb:{tables:Object.fromEntries(s.map((a)=>[`${r}-${a.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:`${r}-events`,subscriptions:s.map((a)=>({protocol:"sqs",endpoint:`${r}-${a.name}-queue`,filterPolicy:{service:[a.name]}}))}}},monitoring:{dashboard:{name:`${r}-microservices`,widgets:s.map((a)=>({type:"metric",metrics:[{service:a.name,metric:"CPUUtilization"},{service:a.name,metric:"MemoryUtilization"},{service:a.name,metric:"RequestCount"}]}))},alarms:s.flatMap((a)=>[{name:`${a.name}-high-cpu`,metric:"CPUUtilization",threshold:80,service:a.name},{name:`${a.name}-errors`,metric:"Errors",threshold:10,service:a.name}])},security:{certificate:{domain:i,validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}}}}}function zm(e){let{name:n,slug:r,domain:i}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i}},infrastructure:{apiGateway:{type:"websocket",customDomain:i?{domain:i,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:`${r}-messages`,startingPosition:"LATEST",batchSize:100}]}},databases:{dynamodb:{tables:{[`${r}-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"}]},[`${r}-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"}]},[`${r}-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:`${r}-realtime`,widgets:[{type:"metric",metrics:["WebSocketConnections","MessagesSent","IntegrationLatency"]}]}},security:{certificate:i?{domain:i,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","connectionLimit"]}}}}}function Hm(e){let{name:n,slug:r,retentionDays:i=7}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",infrastructure:{streaming:{dataStream:{name:`${r}-stream`,shardCount:2,retentionPeriod:i*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:`${r}-stream`,batchSize:1000,startingPosition:"LATEST",parallelizationFactor:10}]},transformer:{runtime:"nodejs20.x",handler:"dist/processors/transform.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${r}-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:`${r}_analytics`,workgroup:`${r}-workgroup`,outputBucket:`${r}-query-results`,tables:[{name:"raw_events",location:`s3://${r}-raw/events/`,format:"parquet",partitionKeys:["year","month","day"]},{name:"processed_events",location:`s3://${r}-processed/events/`,format:"parquet",partitionKeys:["year","month","day"]}]},glue:{crawlers:[{name:`${r}-crawler`,databaseName:`${r}_analytics`,s3Targets:[`s3://${r}-raw/`,`s3://${r}-processed/`],schedule:"cron(0 2 * * ? *)"}],jobs:[{name:`${r}-etl-job`,scriptLocation:`s3://${r}-scripts/etl.py`,role:`${r}-glue-role`,maxCapacity:10,timeout:120}]}},databases:{dynamodb:{tables:{[`${r}-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:`${r}-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:`${r}-pipeline`,widgets:[{type:"metric",metrics:["KinesisIncomingRecords","LambdaInvocations","S3ObjectsCreated","GlueJobsSucceeded"]}]},alarms:[{metric:"LambdaErrors",threshold:10,evaluationPeriods:1},{metric:"KinesisIteratorAge",threshold:60000,evaluationPeriods:2}]}}}}function Gm(e){let{name:n,slug:r,domain:i,modelS3Path:s=`s3://${r}-models/`,instanceType:a="ml.t3.medium"}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i}},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:`${r}-inference`,modelS3Path:s,instanceType:a,initialInstanceCount:1,autoScaling:{minInstances:1,maxInstances:5,targetInvocationsPerInstance:1000}}],trainingJobs:[{name:`${r}-training`,algorithmSpecification:{trainingImage:"TO_BE_SPECIFIED",trainingInputMode:"File"},instanceType:"ml.p3.2xlarge",instanceCount:1,volumeSizeInGB:50,maxRuntimeInSeconds:86400}]}},apiGateway:{type:"HTTP",customDomain:i?{domain:i,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:`${r}-inference`,MODEL_BUCKET:`${r}-models`}},"batch-predict":{runtime:"python3.11",handler:"handlers/batchPredict.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${r}-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:{[`${r}-predictions`]:{partitionKey:{name:"requestId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0},[`${r}-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:`${r}-ml`,widgets:[{type:"metric",metrics:["SageMakerInvocations","SageMakerModelLatency","APIGatewayRequests","LambdaErrors"]}]},alarms:[{metric:"SageMakerModelLatency",threshold:1000,evaluationPeriods:2},{metric:"SageMakerInvocationErrors",threshold:10,evaluationPeriods:1}]},security:{certificate:i?{domain:i,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","apiProtection"]}}}}}function qm(e){let{name:n,slug:r,domain:i,instanceType:s="t3.medium",minInstances:a=2,maxInstances:c=10,databaseEngine:u="mysql",sessionStore:d="redis"}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:i}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:2}},compute:{server:{instanceType:s,ami:"ubuntu-22.04",autoScaling:{min:a,max:c,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
|
|
2454
|
+
| limit 20`,region:t.ref("AWS::Region"),title:`Logs: ${a.logGroup}`}});else if(a.type==="text"&&a.text)r.push({type:"text",x:i,y:s,width:c,height:u,properties:{markdown:a.text}});if(i+=c,i>=24)i=0,s+=u}),e.addResource("CloudWatchDashboard","AWS::CloudWatch::Dashboard",{DashboardName:t.sub(`\${AWS::StackName}-${n.name}`),DashboardBody:JSON.stringify({widgets:r})}),e.addOutputs({DashboardURL:{Description:"CloudWatch Dashboard URL",Value:t.sub("https://console.aws.amazon.com/cloudwatch/home?region=${AWS::Region}#dashboards:name=${CloudWatchDashboard}")}})}function Di(e,n,r){let i=e.toLogicalId(`${n}-log-group`);e.addResource(i,"AWS::Logs::LogGroup",{LogGroupName:t.sub(`/aws/\${AWS::StackName}/${n}`),RetentionInDays:r||14,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}`)}]})}function Tt(e,n){if(n)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"}[n.toLowerCase()]||"AWS/CloudWatch";let r=e.toLowerCase();if(r.includes("cpu")||r.includes("memory")||r.includes("network"))return"AWS/EC2";if(r.includes("lambda")||r.includes("invocation")||r.includes("duration"))return"AWS/Lambda";if(r.includes("request")||r.includes("latency")||r.includes("target"))return"AWS/ApplicationELB";if(r.includes("database")||r.includes("connection"))return"AWS/RDS";if(r.includes("read")||r.includes("write")||r.includes("consumed"))return"AWS/DynamoDB";return"AWS/CloudWatch"}function Ni(e){return{ec2:[{Name:"InstanceId",Value:t.ref("EC2Instance")}],ecs:[{Name:"ClusterName",Value:t.ref("ECSCluster")},{Name:"ServiceName",Value:t.getAtt("ECSService","Name")}],lambda:[{Name:"FunctionName",Value:t.ref("LambdaFunction")}],rds:[{Name:"DBInstanceIdentifier",Value:t.ref("Database")}],dynamodb:[{Name:"TableName",Value:t.ref("DynamoDBTable")}],alb:[{Name:"LoadBalancer",Value:t.getAtt("LoadBalancer","LoadBalancerFullName")}],apigateway:[{Name:"ApiName",Value:t.ref("HttpApi")}]}[e.toLowerCase()]||[]}function wn(e,n){if(!n.vpc)return;let{cidr:r="10.0.0.0/16",availabilityZones:i=2,natGateways:s=1,enableDnsHostnames:a=!0,enableDnsSupport:c=!0}=n.vpc;e.addResource("VPC","AWS::EC2::VPC",{CidrBlock:r,EnableDnsHostnames:a,EnableDnsSupport:c,Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-vpc")}]}),e.addResource("InternetGateway","AWS::EC2::InternetGateway",{Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-igw")}]}),e.addResource("VPCGatewayAttachment","AWS::EC2::VPCGatewayAttachment",{VpcId:t.ref("VPC"),InternetGatewayId:t.ref("InternetGateway")},{dependsOn:["VPC","InternetGateway"]});let u=[];for(let g=0;g<i;g++){let y=`PublicSubnet${g+1}`;u.push(y),e.addResource(y,"AWS::EC2::Subnet",{VpcId:t.ref("VPC"),CidrBlock:t.select(g,t.cidr(t.getAtt("VPC","CidrBlock"),i*2,8)),AvailabilityZone:t.select(g,t.getAZs()),MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-public-${g+1}`)},{Key:"Type",Value:"public"}]},{dependsOn:"VPC"})}let d=[];for(let g=0;g<i;g++){let y=`PrivateSubnet${g+1}`;d.push(y),e.addResource(y,"AWS::EC2::Subnet",{VpcId:t.ref("VPC"),CidrBlock:t.select(g+i,t.cidr(t.getAtt("VPC","CidrBlock"),i*2,8)),AvailabilityZone:t.select(g,t.getAZs()),MapPublicIpOnLaunch:!1,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-private-${g+1}`)},{Key:"Type",Value:"private"}]},{dependsOn:"VPC"})}let m=[];for(let g=0;g<s;g++){let y=`NatEIP${g+1}`;m.push(y),e.addResource(y,"AWS::EC2::EIP",{Domain:"vpc",Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-nat-eip-${g+1}`)}]},{dependsOn:"VPCGatewayAttachment"})}let p=[];for(let g=0;g<s;g++){let y=`NatGateway${g+1}`;p.push(y);let f=g%i;e.addResource(y,"AWS::EC2::NatGateway",{AllocationId:t.getAtt(m[g],"AllocationId"),SubnetId:t.ref(u[f]),Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-nat-${g+1}`)}]},{dependsOn:[m[g],u[f]]})}e.addResource("PublicRouteTable","AWS::EC2::RouteTable",{VpcId:t.ref("VPC"),Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-public-rt")}]},{dependsOn:"VPC"}),e.addResource("PublicRoute","AWS::EC2::Route",{RouteTableId:t.ref("PublicRouteTable"),DestinationCidrBlock:"0.0.0.0/0",GatewayId:t.ref("InternetGateway")},{dependsOn:["PublicRouteTable","VPCGatewayAttachment"]}),u.forEach((g,y)=>{e.addResource(`PublicSubnetRouteTableAssociation${y+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:t.ref(g),RouteTableId:t.ref("PublicRouteTable")},{dependsOn:[g,"PublicRouteTable"]})}),d.forEach((g,y)=>{let f=`PrivateRouteTable${y+1}`,h=y%s;e.addResource(f,"AWS::EC2::RouteTable",{VpcId:t.ref("VPC"),Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-private-rt-${y+1}`)}]},{dependsOn:"VPC"}),e.addResource(`PrivateRoute${y+1}`,"AWS::EC2::Route",{RouteTableId:t.ref(f),DestinationCidrBlock:"0.0.0.0/0",NatGatewayId:t.ref(p[h])},{dependsOn:[f,p[h]]}),e.addResource(`PrivateSubnetRouteTableAssociation${y+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:t.ref(g),RouteTableId:t.ref(f)},{dependsOn:[g,f]})}),e.addResource("S3VPCEndpoint","AWS::EC2::VPCEndpoint",{VpcId:t.ref("VPC"),ServiceName:t.sub("com.amazonaws.${AWS::Region}.s3"),VpcEndpointType:"Gateway",RouteTableIds:[t.ref("PublicRouteTable"),...Array.from({length:i},(g,y)=>t.ref(`PrivateRouteTable${y+1}`))]},{dependsOn:"VPC"}),e.addResource("NetworkAcl","AWS::EC2::NetworkAcl",{VpcId:t.ref("VPC"),Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-nacl")}]},{dependsOn:"VPC"}),e.addResource("NetworkAclEntryInbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:t.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),e.addResource("NetworkAclEntryOutbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:t.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:t.ref("VPC"),Export:{Name:t.sub("${AWS::StackName}-VPC")}},PublicSubnets:{Description:"Public subnet IDs",Value:t.join(",",u.map((g)=>t.ref(g))),Export:{Name:t.sub("${AWS::StackName}-PublicSubnets")}},PrivateSubnets:{Description:"Private subnet IDs",Value:t.join(",",d.map((g)=>t.ref(g))),Export:{Name:t.sub("${AWS::StackName}-PrivateSubnets")}}})}function Mn(e,n){for(let[r,i]of Object.entries(n))xi(e,r,i)}function xi(e,n,r){let i=e.toLogicalId(`${n}-queue`),s=r.fifo||!1,a;if(r.deadLetterQueue){let u=`${i}DLQ`;e.addResource(u,"AWS::SQS::Queue",{QueueName:s?t.sub(`\${AWS::StackName}-${n}-dlq.fifo`):t.sub(`\${AWS::StackName}-${n}-dlq`),FifoQueue:s,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}-dlq`)}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),a=t.getAtt(u,"Arn")}let c={QueueName:s?t.sub(`\${AWS::StackName}-${n}.fifo`):t.sub(`\${AWS::StackName}-${n}`),FifoQueue:s,VisibilityTimeout:r.visibilityTimeout||30,MessageRetentionPeriod:r.messageRetentionPeriod||345600,ReceiveMessageWaitTimeSeconds:r.receiveMessageWaitTime||0,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}`)}]};if(s&&r.contentBasedDeduplication)c.ContentBasedDeduplication=!0;if(r.deadLetterQueue&&a)c.RedrivePolicy={deadLetterTargetArn:a,maxReceiveCount:r.maxReceiveCount||3};if(e.addResource(i,"AWS::SQS::Queue",c,{dependsOn:r.deadLetterQueue?`${i}DLQ`:void 0,deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),e.addResource(`${i}Policy`,"AWS::SQS::QueuePolicy",{Queues:[t.ref(i)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","events.amazonaws.com","sns.amazonaws.com"]},Action:"sqs:SendMessage",Resource:t.getAtt(i,"Arn"),Condition:{ArnEquals:{"aws:SourceArn":t.sub("arn:aws:*:${AWS::Region}:${AWS::AccountId}:*")}}}]}},{dependsOn:i}),e.addOutputs({[`${i}Url`]:{Description:`${n} queue URL`,Value:t.ref(i),Export:{Name:t.sub(`\${AWS::StackName}-${n}-queue-url`)}},[`${i}Arn`]:{Description:`${n} queue ARN`,Value:t.getAtt(i,"Arn"),Export:{Name:t.sub(`\${AWS::StackName}-${n}-queue-arn`)}}}),r.deadLetterQueue)e.addOutputs({[`${i}DLQUrl`]:{Description:`${n} dead letter queue URL`,Value:t.ref(`${i}DLQ`),Export:{Name:t.sub(`\${AWS::StackName}-${n}-dlq-url`)}}})}function Ln(e,n){if(n.certificate)ki(e,n.certificate);if(n.waf?.enabled)Mi(e,n.waf);if(n.securityGroups)for(let[r,i]of Object.entries(n.securityGroups))Li(e,r,i)}function ki(e,n){if(!n)return;let r=[n.domain];if(n.subdomains)r.push(...n.subdomains);e.addResource("Certificate","AWS::CertificateManager::Certificate",{DomainName:n.domain,SubjectAlternativeNames:n.subdomains,ValidationMethod:n.validationMethod||"DNS",DomainValidationOptions:r.map((i)=>({DomainName:i,HostedZoneId:t.ref("HostedZone")})),Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-certificate")}]}),e.addOutputs({CertificateArn:{Description:"ACM Certificate ARN",Value:t.ref("Certificate"),Export:{Name:t.sub("${AWS::StackName}-certificate-arn")}}})}function Mi(e,n){if(!n)return;let r=[],i=n.rules||["rateLimit","sqlInjection","xss"];if(i.includes("rateLimit"))r.push({Name:"RateLimitRule",Priority:1,Statement:{RateBasedStatement:{Limit:n.rateLimit||2000,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"RateLimitRule"}});let s=r.length+1;if(i.includes("sqlInjection"))r.push({Name:"AWSManagedRulesSQLi",Priority:s++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesSQLiRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesSQLi"}});if(i.includes("xss"))r.push({Name:"AWSManagedRulesXSS",Priority:s++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesXSS"}});if(i.includes("knownBadInputs"))r.push({Name:"AWSManagedRulesKnownBadInputs",Priority:s++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesKnownBadInputs"}});if(i.includes("coreRuleSet"))r.push({Name:"AWSManagedRulesCoreRuleSet",Priority:s++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesCommonRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesCoreRuleSet"}});if(i.includes("linuxRuleSet"))r.push({Name:"AWSManagedRulesLinuxRuleSet",Priority:s++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesLinuxRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesLinuxRuleSet"}});if(i.includes("apiProtection"))r.push({Name:"AWSManagedRulesAPIProtection",Priority:s++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesAmazonIpReputationList"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesAPIProtection"}});if(i.includes("geoBlock"))r.push({Name:"GeoBlockRule",Priority:s++,Statement:{GeoMatchStatement:{CountryCodes:["CN","RU"]}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"GeoBlockRule"}});if(i.includes("connectionLimit"))r.push({Name:"ConnectionLimitRule",Priority:s++,Statement:{RateBasedStatement:{Limit:100,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"ConnectionLimitRule"}});if(e.addResource("WebACL","AWS::WAFv2::WebACL",{Name:t.sub("${AWS::StackName}-waf"),Scope:n.scope||"REGIONAL",DefaultAction:{Allow:{}},Rules:r,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:t.sub("${AWS::StackName}-waf")},Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-waf")}]}),e.hasResource("LoadBalancer"))e.addResource("WebACLAssociation","AWS::WAFv2::WebACLAssociation",{ResourceArn:t.ref("LoadBalancer"),WebACLArn:t.getAtt("WebACL","Arn")},{dependsOn:["WebACL","LoadBalancer"]});e.addOutputs({WebACLId:{Description:"WAF Web ACL ID",Value:t.ref("WebACL"),Export:{Name:t.sub("${AWS::StackName}-waf-id")}},WebACLArn:{Description:"WAF Web ACL ARN",Value:t.getAtt("WebACL","Arn"),Export:{Name:t.sub("${AWS::StackName}-waf-arn")}}})}function Li(e,n,r){if(!r)return;let i=e.toLogicalId(`${n}-security-group`),s=r.ingress?.map((c)=>({IpProtocol:c.protocol,FromPort:c.port,ToPort:c.port,CidrIp:c.cidr,SourceSecurityGroupId:c.source?t.ref(c.source):void 0}))||[],a=r.egress?.map((c)=>({IpProtocol:c.protocol,FromPort:c.port,ToPort:c.port,CidrIp:c.cidr||"0.0.0.0/0"}))||[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}];e.addResource(i,"AWS::EC2::SecurityGroup",{GroupDescription:`Security group for ${n}`,VpcId:t.ref("VPC"),SecurityGroupIngress:s,SecurityGroupEgress:a,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}-sg`)}]},{dependsOn:"VPC"}),e.addOutputs({[`${i}Id`]:{Description:`${n} security group ID`,Value:t.ref(i),Export:{Name:t.sub(`\${AWS::StackName}-${n}-sg-id`)}}})}function $n(e,n){for(let[r,i]of Object.entries(n)){if(i.type==="efs"){$i(e,r,i);continue}Oi(e,r,i)}}function Oi(e,n,r){let i=e.toLogicalId(`${n}-bucket`),s={BucketName:t.sub(`\${AWS::StackName}-${n}`),Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}`)}]};if(r.versioning)s.VersioningConfiguration={Status:"Enabled"};if(r.encryption)s.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(!r.public)s.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(r.website)s.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"index.html"};if(r.cors&&r.cors.length>0)s.CorsConfiguration={CorsRules:r.cors.map((a)=>({AllowedOrigins:a.allowedOrigins,AllowedMethods:a.allowedMethods,AllowedHeaders:a.allowedHeaders||["*"],MaxAge:a.maxAge||3600}))};if(r.lifecycleRules&&r.lifecycleRules.length>0)s.LifecycleConfiguration={Rules:r.lifecycleRules.map((a)=>({Id:a.id,Status:a.enabled?"Enabled":"Disabled",ExpirationInDays:a.expirationDays,Transitions:a.transitions?.map((c)=>({TransitionInDays:c.days,StorageClass:c.storageClass}))}))};if(r.intelligentTiering)s.IntelligentTieringConfigurations=[{Id:"EntireBucket",Status:"Enabled",Tierings:[{AccessTier:"ARCHIVE_ACCESS",Days:90},{AccessTier:"DEEP_ARCHIVE_ACCESS",Days:180}]}];if(e.addResource(i,"AWS::S3::Bucket",s,{deletionPolicy:r.versioning?"Retain":"Delete"}),r.public)e.addResource(`${i}Policy`,"AWS::S3::BucketPolicy",{Bucket:t.ref(i),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:"s3:GetObject",Resource:t.join("",[Pn.s3Bucket(t.ref(i)),"/*"])}]}},{dependsOn:i});if(e.addOutputs({[`${i}Name`]:{Description:`${n} bucket name`,Value:t.ref(i),Export:{Name:t.sub(`\${AWS::StackName}-${n}-bucket`)}},[`${i}Arn`]:{Description:`${n} bucket ARN`,Value:t.getAtt(i,"Arn"),Export:{Name:t.sub(`\${AWS::StackName}-${n}-bucket-arn`)}}}),r.website)e.addOutputs({[`${i}WebsiteURL`]:{Description:`${n} website URL`,Value:t.getAtt(i,"WebsiteURL")}})}function $i(e,n,r){let i=e.toLogicalId(`${n}-efs`),s={Encrypted:r.encryption!==!1,PerformanceMode:r.performanceMode||"generalPurpose",ThroughputMode:r.throughputMode||"bursting",FileSystemTags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}`)}]};if(r.lifecyclePolicy){if(s.LifecyclePolicies=[],r.lifecyclePolicy.transitionToIA)s.LifecyclePolicies.push({TransitionToIA:`AFTER_${r.lifecyclePolicy.transitionToIA}_DAYS`});if(r.lifecyclePolicy.transitionToPrimaryStorageClass)s.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"})}e.addResource(i,"AWS::EFS::FileSystem",s,{deletionPolicy:"Retain"});let a=2;for(let c=0;c<a;c++)e.addResource(`${i}MountTarget${c+1}`,"AWS::EFS::MountTarget",{FileSystemId:t.ref(i),SubnetId:t.ref(`PrivateSubnet${c+1}`),SecurityGroups:[t.ref("EFSSecurityGroup")]},{dependsOn:[i,`PrivateSubnet${c+1}`]});e.addResource("EFSSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for EFS mount targets",VpcId:t.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:t.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:t.sub("${AWS::StackName}-efs-sg")}]},{dependsOn:"VPC"}),e.addOutputs({[`${i}Id`]:{Description:`${n} EFS file system ID`,Value:t.ref(i),Export:{Name:t.sub(`\${AWS::StackName}-${n}-efs`)}}})}class wl{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:t.equals(t.ref("Environment"),"production"),HasDomain:t.not([t.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:t.ref("AWS::StackName"),Export:{Name:t.sub("${AWS::StackName}-Name")}},Region:{Description:"AWS Region",Value:t.ref("AWS::Region"),Export:{Name:t.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,n,r,i){let s={Type:n,Properties:r};if(i?.dependsOn)s.DependsOn=i.dependsOn,this.trackDependency(e,i.dependsOn);if(i?.condition)s.Condition=i.condition;if(i?.deletionPolicy)s.DeletionPolicy=i.deletionPolicy;if(i?.updateReplacePolicy)s.UpdateReplacePolicy=i.updateReplacePolicy;this.template.Resources[e]=s}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,n){if(!this.resourceDependencies.has(e))this.resourceDependencies.set(e,new Set);(Array.isArray(n)?n:[n]).forEach((i)=>this.resourceDependencies.get(e).add(i))}resolveDependencies(){let e=new Set,n=new Set,r=(i)=>{if(n.has(i))throw Error(`Circular dependency detected involving resource: ${i}`);if(e.has(i))return!0;e.add(i),n.add(i);let s=this.resourceDependencies.get(i);if(s)for(let a of s)r(a);return n.delete(i),!0};for(let i of this.resourceDependencies.keys())r(i)}toLogicalId(e){return e.split(/[-_\s]/).map((n)=>n.charAt(0).toUpperCase()+n.slice(1).toLowerCase()).join("")}addNetworkResources(e){wn(this,e)}addStorageResources(e){$n(this,e)}addComputeResources(e){bn(this,e)}addDatabaseResources(e){Cn(this,e)}addFunctionResources(e){vn(this,e)}addCacheResources(e){yn(this,e)}addQueueResources(e){Mn(this,e)}addMessagingResources(e){Tn(this,e)}addCDNResources(e){fn(this,e)}addApiGatewayResources(e){gn(this,e)}addMonitoringResources(e){En(this,e)}addSecurityResources(e){Ln(this,e)}}function La(e){return new wl(e).build()}function qm(e){let{name:n,slug:r,domain:i,subdomain:s}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:s&&i?`${s}.${i}`:i}},infrastructure:{storage:{assets:{public:!0,versioning:!1,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"],allowedHeaders:["*"],maxAge:3600}]}},cdn:{enabled:!0,customDomain:i?{domain:s&&i?`${s}.${i}`:i,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 Wm(e){let{name:n,slug:r,domain:i,instanceType:s="t3.small",minInstances:a=2,maxInstances:c=10}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:i}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:s,ami:"ubuntu-22.04",keyPair:`${r}-key`,autoScaling:{min:a,max:c,desired:a,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:i?{domain:i,subdomains:[`*.${i}`],validationMethod:"DNS"}:void 0}}}}function Km(e){let{name:n,slug:r,domain:i,taskCpu:s="256",taskMemory:a="512",desiredCount:c=2}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:0}},compute:{fargate:{taskDefinition:{cpu:s,memory:a,containerDefinitions:[{name:"app",image:`${r}-app:latest`,portMappings:[{containerPort:3000}],environment:[],secrets:[]}]},service:{desiredCount:c,healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},autoScaling:{min:c,max:c*5,targetCPU:70,targetMemory:80}},loadBalancer:{type:"application"}}},databases:{dynamodb:{tables:{[`${r}-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:`${r}-queue`}]}},security:{certificate:i?{domain:i,subdomains:[`*.${i}`],validationMethod:"DNS"}:void 0}}}}function Jm(e){let{name:n,slug:r,entry:i,domain:s,runtime:a="nodejs20.x",memory:c=1024,build:u,deploy:d,assets:m,queues:p=!0,scheduler:g="on",region:y="us-east-1"}=e;return{project:{name:n,slug:r,region:y},mode:"serverless",environments:{production:{type:"production",domain:s,app:{kind:"node",runtime:a,entry:i,memory:c,build:u,deploy:d,assets:m,queues:p,scheduler:g,domain:s}}}}}function Ma(e){let n=e.database!==!1,r=e.cache!==!1,i=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:t.ref("AWS::Region")},...n?[{name:"DB_HOST",value:t.getAtt("PostgresDb","Endpoint.Address")},{name:"DB_PORT",value:t.getAtt("PostgresDb","Endpoint.Port")}]:[],...r?[{name:"REDIS_HOST",value:t.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address")},{name:"REDIS_PORT",value:t.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port")},{name:"REDIS_TLS",value:"true"}]:[],...i?[{name:"QUEUE_URL",value:t.ref("JobsQueue")}]:[],{name:"MAIL_TRANSPORT",value:"ses"}],secrets:n?[{name:"DB_USERNAME",valueFrom:t.sub("${DBSecret}:username::")},{name:"DB_PASSWORD",valueFrom:t.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}}:{}}}},...n?{databases:{postgres:{engine:"postgres",version:"16",instanceClass:"db.t4g.micro",allocatedStorage:20,maxAllocatedStorage:100,multiAZ:!1,backupRetentionDays:7,deletionProtection:!0}}}:{},...r?{cache:{redis:{nodeType:"cache.t4g.micro",numCacheNodes:2,engine:"redis",engineVersion:"7.1",automaticFailoverEnabled:!0,snapshotRetentionLimit:5}}}:{},...i?{queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0,maxReceiveCount:3,receiveMessageWaitTime:20}}}:{}}}}function Xm(e){let{name:n,slug:r,domain:i,apiSubdomain:s="api"}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:i}},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:i,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:`${r}-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:`${s}.${i}`,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:i,subdomains:[`*.${i}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss"]}}}}}function Qm(e){let{name:n,slug:r,domain:i}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i}},infrastructure:{apiGateway:{type:"HTTP",cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"],allowHeaders:["Content-Type","Authorization"],maxAge:3600},customDomain:i?{domain:i,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:{[`${r}-users`]:{partitionKey:{name:"userId",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"EmailIndex",partitionKey:{name:"email",type:"S"},projection:"ALL"}]},[`${r}-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:i?{domain:i,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 Ym(e){let{name:n,slug:r,domain:i,instanceType:s="t3.small"}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:i}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:s,ami:"ubuntu-22.04",keyPair:`${r}-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:i,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,origins:[{type:"alb",pathPattern:"/wp-content/*"}]},security:{certificate:{domain:i,subdomains:[`www.${i}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","wordpressRules"]}}}}}function Zm(e){let{name:n,slug:r,domain:i,apiDomain:s}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i}},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:i,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},...s?{api:{runtime:"nodejs20.x",handler:"dist/api/index.handler",memory:1024,timeout:30,events:[{type:"http",path:"/{proxy+}",method:"ANY"}]}}:{}},apiGateway:s?{type:"HTTP",customDomain:{domain:s,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:[i],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:i,subdomains:s?[s]:[],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","geoBlock"]}}}}}function eg(e){let{name:n,slug:r,domain:i,services:s}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:3,natGateways:2}},compute:{services:s.map((a)=>({name:a.name,type:"fargate",taskDefinition:{cpu:a.cpu||"256",memory:a.memory||"512",containerDefinitions:[{name:a.name,image:`${r}-${a.name}:latest`,portMappings:[{containerPort:a.port}],healthCheck:{command:["CMD-SHELL",`curl -f http://localhost:${a.port}/health || exit 1`],interval:30,timeout:5,retries:3}}]},service:{desiredCount:a.desiredCount||2,serviceDiscovery:{enabled:!0,namespace:`${r}.local`},autoScaling:{min:2,max:10,targetCPU:70}}}))},apiGateway:{type:"HTTP",customDomain:{domain:i,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"]},routes:s.map((a)=>({path:`/${a.name}/{proxy+}`,integration:{type:"vpc-link",service:a.name}}))},databases:{dynamodb:{tables:Object.fromEntries(s.map((a)=>[`${r}-${a.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:`${r}-events`,subscriptions:s.map((a)=>({protocol:"sqs",endpoint:`${r}-${a.name}-queue`,filterPolicy:{service:[a.name]}}))}}},monitoring:{dashboard:{name:`${r}-microservices`,widgets:s.map((a)=>({type:"metric",metrics:[{service:a.name,metric:"CPUUtilization"},{service:a.name,metric:"MemoryUtilization"},{service:a.name,metric:"RequestCount"}]}))},alarms:s.flatMap((a)=>[{name:`${a.name}-high-cpu`,metric:"CPUUtilization",threshold:80,service:a.name},{name:`${a.name}-errors`,metric:"Errors",threshold:10,service:a.name}])},security:{certificate:{domain:i,validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}}}}}function tg(e){let{name:n,slug:r,domain:i}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i}},infrastructure:{apiGateway:{type:"websocket",customDomain:i?{domain:i,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:`${r}-messages`,startingPosition:"LATEST",batchSize:100}]}},databases:{dynamodb:{tables:{[`${r}-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"}]},[`${r}-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"}]},[`${r}-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:`${r}-realtime`,widgets:[{type:"metric",metrics:["WebSocketConnections","MessagesSent","IntegrationLatency"]}]}},security:{certificate:i?{domain:i,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","connectionLimit"]}}}}}function rg(e){let{name:n,slug:r,retentionDays:i=7}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",infrastructure:{streaming:{dataStream:{name:`${r}-stream`,shardCount:2,retentionPeriod:i*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:`${r}-stream`,batchSize:1000,startingPosition:"LATEST",parallelizationFactor:10}]},transformer:{runtime:"nodejs20.x",handler:"dist/processors/transform.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${r}-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:`${r}_analytics`,workgroup:`${r}-workgroup`,outputBucket:`${r}-query-results`,tables:[{name:"raw_events",location:`s3://${r}-raw/events/`,format:"parquet",partitionKeys:["year","month","day"]},{name:"processed_events",location:`s3://${r}-processed/events/`,format:"parquet",partitionKeys:["year","month","day"]}]},glue:{crawlers:[{name:`${r}-crawler`,databaseName:`${r}_analytics`,s3Targets:[`s3://${r}-raw/`,`s3://${r}-processed/`],schedule:"cron(0 2 * * ? *)"}],jobs:[{name:`${r}-etl-job`,scriptLocation:`s3://${r}-scripts/etl.py`,role:`${r}-glue-role`,maxCapacity:10,timeout:120}]}},databases:{dynamodb:{tables:{[`${r}-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:`${r}-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:`${r}-pipeline`,widgets:[{type:"metric",metrics:["KinesisIncomingRecords","LambdaInvocations","S3ObjectsCreated","GlueJobsSucceeded"]}]},alarms:[{metric:"LambdaErrors",threshold:10,evaluationPeriods:1},{metric:"KinesisIteratorAge",threshold:60000,evaluationPeriods:2}]}}}}function ng(e){let{name:n,slug:r,domain:i,modelS3Path:s=`s3://${r}-models/`,instanceType:a="ml.t3.medium"}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:i}},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:`${r}-inference`,modelS3Path:s,instanceType:a,initialInstanceCount:1,autoScaling:{minInstances:1,maxInstances:5,targetInvocationsPerInstance:1000}}],trainingJobs:[{name:`${r}-training`,algorithmSpecification:{trainingImage:"TO_BE_SPECIFIED",trainingInputMode:"File"},instanceType:"ml.p3.2xlarge",instanceCount:1,volumeSizeInGB:50,maxRuntimeInSeconds:86400}]}},apiGateway:{type:"HTTP",customDomain:i?{domain:i,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:`${r}-inference`,MODEL_BUCKET:`${r}-models`}},"batch-predict":{runtime:"python3.11",handler:"handlers/batchPredict.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${r}-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:{[`${r}-predictions`]:{partitionKey:{name:"requestId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0},[`${r}-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:`${r}-ml`,widgets:[{type:"metric",metrics:["SageMakerInvocations","SageMakerModelLatency","APIGatewayRequests","LambdaErrors"]}]},alarms:[{metric:"SageMakerModelLatency",threshold:1000,evaluationPeriods:2},{metric:"SageMakerInvocationErrors",threshold:10,evaluationPeriods:1}]},security:{certificate:i?{domain:i,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","apiProtection"]}}}}}function ig(e){let{name:n,slug:r,domain:i,instanceType:s="t3.medium",minInstances:a=2,maxInstances:c=10,databaseEngine:u="mysql",sessionStore:d="redis"}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:i}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:2}},compute:{server:{instanceType:s,ami:"ubuntu-22.04",autoScaling:{min:a,max:c,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
|
|
2455
2455
|
# Install Node.js or PHP/Python based on app needs
|
|
2456
2456
|
# Configure application server (PM2, Nginx, Apache)
|
|
2457
2457
|
# Mount EFS for shared file storage
|
|
2458
|
-
`}},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:[i||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${r}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:i?{domain:i,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:u==="mysql"?{mysql:{engine:"mysql",version:"8.0",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",innodb_buffer_pool_size:"{DBInstanceClassMemory*3/4}",slow_query_log:"1",long_query_time:"2"}}}:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",shared_buffers:"{DBInstanceClassMemory/4}",log_min_duration_statement:"2000"}}},cache:d==="redis"?{redis:{nodeType:"cache.t3.medium",numCacheNodes:2,engine:"redis",engineVersion:"7.0",port:6379,parameterGroup:{maxmemoryPolicy:"allkeys-lru",timeout:"300"},snapshotRetentionLimit:5,snapshotWindow:"03:00-05:00",automaticFailoverEnabled:!0}}:void 0,queues:{jobs:{fifo:!1,visibilityTimeout:900,messageRetentionPeriod:345600,receiveMessageWaitTime:20,deadLetterQueue:!0,maxReceiveCount:3},emails:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:86400,deadLetterQueue:!0}},functions:{"job-worker":{runtime:"nodejs20.x",handler:"dist/workers/jobs.handler",memory:2048,timeout:900,events:[{type:"sqs",queueName:`${r}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${r}-emails`,batchSize:10}]},cleanup:{runtime:"nodejs20.x",handler:"dist/tasks/cleanup.handler",memory:512,timeout:300,events:[{type:"schedule",expression:"cron(0 2 * * ? *)"}]}},monitoring:{dashboard:{name:`${r}-web-app`,widgets:[{type:"metric",metrics:["EC2CPUUtilization","ALBRequestCount","ALBTargetResponseTime","RDSCPUUtilization","RDSDatabaseConnections","RDSReadLatency","RDSWriteLatency"]}]},alarms:[{metric:"EC2CPUUtilization",threshold:80,evaluationPeriods:2},{metric:"RDSCPUUtilization",threshold:80,evaluationPeriods:2},{metric:"RDSDatabaseConnections",threshold:400,evaluationPeriods:1},{metric:"ALBTargetResponseTime",threshold:2000,evaluationPeriods:2},{metric:"ALBUnhealthyHostCount",threshold:1,evaluationPeriods:1}],logs:{retention:14,groups:[`${r}-app`,`${r}-nginx`,`${r}-workers`]}},security:{certificate:i?{domain:i,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","knownBadInputs"]},securityGroups:{alb:{ingress:[{port:80,protocol:"tcp",cidr:"0.0.0.0/0"},{port:443,protocol:"tcp",cidr:"0.0.0.0/0"}]},app:{ingress:[{port:3000,protocol:"tcp",source:"alb-sg"}]},database:{ingress:[{port:u==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...d==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function Wm(e){let{name:n,slug:r,domain:i,repository:s,phpVersion:a="8.3",size:c="small",database:u=r.replace(/-/g,"_"),databasePassword:d,sslEmail:m,deployStrategy:p="push",provider:g="hetzner"}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"server",cloud:{provider:g},environments:{production:{type:"production",domain:i}},infrastructure:{compute:{mode:"server",size:c,runtime:"php",webServer:"nginx",php:{versions:[a],default:a},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:u,username:u,password:d}},sites:{main:{root:".",type:"laravel",domain:i,phpVersion:a,repository:{...s,strategy:p},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:m}}}}}function Km(e){let{name:n,slug:r,domain:i,layers:s,phpVersion:a="8.3",architecture:c="x86_64",memory:u=1024,build:d,deploy:m=["migrate --force"],cache:p="dynamodb",scheduler:g="on",region:y="us-east-1"}=e;return{project:{name:n,slug:r,region:y},mode:"serverless",environments:{production:{type:"production",domain:i,app:{kind:"php",runtime:"provided.al2023",phpVersion:a,architecture:c,layers:s,memory:u,build:d,deploy:m,assets:"public",queues:!0,scheduler:g,cache:{driver:p},domain:i}}}}}function Jm(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 hu=ua,yu="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function Si(e){let n=e.split(".").filter(Boolean);return n.length<=2?e:n.slice(-2).join(".")}function Ai(e){let n=2166136261;for(let r=0;r<e.length;r++)n^=e.charCodeAt(r),n=Math.imul(n,16777619);return n>>>0}var bu=20000,Su=12000;function vu(e){return bu+Ai(e)%Su}function Mn(e,n){let r=Si(e);if(r===e)return`dashboard.${r}`;for(let i of n)if(i===r)return`dashboard.${r}`;return`dashboard.${e}`}function Ln(e,n){let r=[],i=e.infrastructure?.dns?.domain;if(i&&!e.cloud?.attachTo)r.push(i);if(n&&e.environments?.[n]?.domain)r.push(e.environments[n].domain);for(let s of Object.values(e.sites??{})){let a=s;if(!a||a.redirect)continue;let c=a.domain;if(typeof c==="string")r.push(c);else if(Array.isArray(c))r.push(...c.filter((u)=>typeof u==="string"))}return r.filter((s)=>s&&!s.startsWith("dashboard."))}function Cu(e,n,r){if(r)return r;let i=Ln(e,n),s=i[0];if(!s)return null;return Mn(s,i)}function Tu(e,n,r){if(r)return[r];let i=Ln(e,n),s=[];for(let a of i){let c=Mn(a,i);if(!s.includes(c))s.push(c)}return s}function er(e){return Object.entries(e.sites??{}).some(([n,r])=>{if(!r)return!1;let i=r.root??"";return Vr(n)||i==="ui/dist"||i.endsWith("/ui/dist")||i.endsWith("/dist/ui")})}var hl="dashboard-";function yl(e){return hl+e.replace(/^dashboard\./,"").replace(/\./g,"-")}function Vr(e){return e==="dashboard"||e.startsWith(hl)}function Gi(e,n,r){if(er(e))return[];if(e.cloud?.attachTo)return[];let i=r.password?{auth:{username:r.username||"admin",password:r.password,realm:r.realm}}:{},s=r.build===!1||r.build===void 0?{}:{build:r.build};if(r.live!==!1){let c=Cu(e,n,r.domain);if(!c)return[];let u=r.port??vu(c),d=e.infrastructure?.appDatabase??e.infrastructure?.compute?.database,m={root:r.uiRoot,deploy:"server",domain:c,preStart:["bun install --production --no-save"],start:`bun ${yu} --box --host 127.0.0.1 --port ${u}`,port:u,cpuWeight:10,ioWeight:10,tasksMax:128,env:{APP_ENV:"production",NODE_ENV:"production",TS_CLOUD_DASHBOARD_TELEMETRY:"1",...d?.password?{TS_CLOUD_DASHBOARD_DB_PASSWORD:d.password}:{}},zeroDowntime:!1,sharedPaths:[hu],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:yl(c),site:m}]}return Tu(e,n,r.domain).map((c)=>({name:yl(c),site:{root:r.uiRoot,deploy:"server",type:"static",domain:c,ssl:{provider:"letsencrypt"},...s,...i}}))}function Xm(e,n,r){return Gi(e,n,r)[0]??null}function Ct(e,n){let r={...e};for(let i in n){let s=n[i],a=r[i];if(s===void 0)continue;if(Array.isArray(s)&&Array.isArray(a))r[i]=[...a,...s];else if(typeof s==="object"&&s!==null&&!Array.isArray(s)&&typeof a==="object"&&a!==null&&!Array.isArray(a))r[i]=Ct(a,s);else r[i]=s}return r}function bl(e,n){return Ct(e,n)}function Qm(...e){return e.reduce((n,r)=>Ct(n,r),{})}function Ym(e,n){return(r)=>{let i=e(r);if(typeof n==="function")return bl(i,n(i,r));return bl(i,n)}}function Pn(e){return{infrastructure:e}}function Zm(e){return Pn({monitoring:e})}function eg(e){return Pn({security:e})}function tg(e){return Pn({databases:e})}function rg(e){return Pn({cache:e})}function ng(e){return Pn({cdn:e})}function ig(e){return Pn({queues:e})}import{existsSync as On,readFileSync as vt}from"node:fs";import{homedir as $n}from"node:os";import{join as Bn}from"node:path";function Eu(){let e=process.env.AWS_ACCESS_KEY_ID,n=process.env.AWS_SECRET_ACCESS_KEY;if(!e||!n)return null;return{accessKeyId:e,secretAccessKey:n,sessionToken:process.env.AWS_SESSION_TOKEN}}function wu(e){let n=e?.profile||process.env.AWS_PROFILE||"default",r=e?.credentialsFile||Bn($n(),".aws","credentials");if(!On(r))return null;try{let i=vt(r,"utf-8");return Ci(i,n)}catch{return null}}function Ci(e,n){let r=e.split(`
|
|
2459
|
-
`),i=null,s,a,c;for(let u of r){let d=u.trim();if(!d||d.startsWith("#")||d.startsWith(";"))continue;let m=d.match(/^\[([^\]]+)\]$/);if(m){if(i===n&&s&&a)return{accessKeyId:s,secretAccessKey:a,sessionToken:c};i=m[1],s=void 0,a=void 0,c=void 0;continue}if(i===n){let[p,...g]=d.split("="),y=g.join("=").trim();switch(p.trim().toLowerCase()){case"aws_access_key_id":s=y;break;case"aws_secret_access_key":a=y;break;case"aws_session_token":c=y;break}}}if(i===n&&s&&a)return{accessKeyId:s,secretAccessKey:a,sessionToken:c};return null}async function Au(e){let n=e?.timeout??1000,r="http://169.254.169.254";try{let i=await je("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},n);if(!i.ok)return null;let s=await i.text(),a=await je("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":s}},n);if(!a.ok)return null;let c=(await a.text()).trim(),u=await je(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${c}`,{headers:{"X-aws-ec2-metadata-token":s}},n);if(!u.ok)return null;let d=await u.json();return{accessKeyId:d.AccessKeyId,secretAccessKey:d.SecretAccessKey,sessionToken:d.Token,expiration:new Date(d.Expiration)}}catch{return null}}async function Ru(e){let n=e?.timeout??1000,r=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,i=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,s=null;if(r)s=`http://169.254.170.2${r}`;else if(i)s=i;if(!s)return null;try{let a={},c=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(c)a.Authorization=c;let u=await je(s,{headers:a},n);if(!u.ok)return null;let d=await u.json();return{accessKeyId:d.AccessKeyId,secretAccessKey:d.SecretAccessKey,sessionToken:d.Token,expiration:new Date(d.Expiration)}}catch{return null}}async function Iu(e){let n=e?.timeout??5000,r=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,i=process.env.AWS_ROLE_ARN,s=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!r||!i)return null;try{let a=vt(r,"utf-8").trim(),c=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION||"us-east-1",u=c.startsWith("us-gov")?`https://sts.${c}.amazonaws.com`:c==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${c}.amazonaws.com`,d=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:i,RoleSessionName:s,WebIdentityToken:a}),m=await je(`${u}/?${d.toString()}`,{method:"POST"},n);if(!m.ok)return null;let p=await m.text(),g=Ue(p,"AccessKeyId"),y=Ue(p,"SecretAccessKey"),f=Ue(p,"SessionToken"),h=Ue(p,"Expiration");if(!g||!y)return null;return{accessKeyId:g,secretAccessKey:y,sessionToken:f??void 0,expiration:h?new Date(h):void 0}}catch{return null}}async function qi(e){let n=Eu();if(n)return n;let r=wu(e);if(r)return r;let i=await Iu(e);if(i)return i;let s=await Ru(e);if(s)return s;let a=await Au(e);if(a)return a;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 og(e){let n=null,r=null;return async()=>{if(n){if(!n.expiration)return n;let i=300000;if(n.expiration.getTime()-Date.now()>i)return n}if(r)return r;return r=qi(e).then((i)=>(n=i,r=null,i)).catch((i)=>{throw r=null,i}),r}}async function je(e,n,r){let i=new AbortController,s=setTimeout(()=>i.abort(),r);try{let a=await fetch(e,{...n,signal:i.signal});return clearTimeout(s),a}catch(a){throw clearTimeout(s),a}}function Ue(e,n){let r=new RegExp(`<${n}>([^<]+)</${n}>`),i=e.match(r);return i?i[1]:null}async function Dn(e){return qi({profile:e})}function Pu(e){let n=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(n)return n;let r=Bn($n(),".aws","config");if(On(r))try{let i=vt(r,"utf-8"),s=e||process.env.AWS_PROFILE||"default",a=s==="default"?"[default]":`[profile ${s}]`,c=i.split(`
|
|
2460
|
-
`),u=!1;for(let d of c){let m=d.trim();if(m.startsWith("[")){u=m===a;continue}if(u&&m.startsWith("region")){let[,p]=m.split("=");if(p)return p.trim()}}}catch{}return"us-east-1"}async function Sl(e){let n=e||await qi(),r=Pu(),{signRequest:i}=await import("./chunk-7haewmr7.js"),s=r.startsWith("us-gov")?`https://sts.${r}.amazonaws.com`:r==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${r}.amazonaws.com`,a="Action=GetCallerIdentity&Version=2011-06-15",c=i({method:"POST",url:s,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...n,service:"sts",region:r}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:c.body});if(!u.ok)throw Error(`Failed to get account ID: ${await u.text()}`);let d=await u.text(),m=Ue(d,"Account");if(!m)throw Error("Failed to parse account ID from response");return m}class Du{profile;credentials=null;region;constructor(e="us-east-1",n="default"){this.profile=n;this.region=e}async init(){if(this.credentials=await Dn(this.profile),this.credentials.region)this.region=this.credentials.region}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async request(e,n){let r=await this.ensureCredentials(),i={Action:e,Version:"2010-05-15",...Tt(n)},s=new URLSearchParams(i).toString(),c=await(await Ot({method:"POST",url:`https://cloudformation.${this.region}.amazonaws.com/`,service:"cloudformation",region:this.region,headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken})).text();return vi(c)}async createStack(e){let n={StackName:e.stackName};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;else throw Error("Either templateBody or templateURL must be provided");if(e.parameters)for(let[s,[a,c]]of Object.entries(e.parameters).entries())n[`Parameters.member.${s+1}.ParameterKey`]=a,n[`Parameters.member.${s+1}.ParameterValue`]=c;if(e.capabilities)for(let[s,a]of e.capabilities.entries())n[`Capabilities.member.${s+1}`]=a;if(e.tags)for(let[s,[a,c]]of Object.entries(e.tags).entries())n[`Tags.member.${s+1}.Key`]=a,n[`Tags.member.${s+1}.Value`]=c;if(e.timeoutInMinutes)n.TimeoutInMinutes=e.timeoutInMinutes;if(e.onFailure)n.OnFailure=e.onFailure;let r=await this.request("CreateStack",n);return(r?.CreateStackResult||r?.CreateStackResponse?.CreateStackResult||r)?.StackId}async updateStack(e){let n={StackName:e.stackName};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;if(e.parameters)for(let[s,[a,c]]of Object.entries(e.parameters).entries())n[`Parameters.member.${s+1}.ParameterKey`]=a,n[`Parameters.member.${s+1}.ParameterValue`]=c;if(e.capabilities)for(let[s,a]of e.capabilities.entries())n[`Capabilities.member.${s+1}`]=a;if(e.tags)for(let[s,[a,c]]of Object.entries(e.tags).entries())n[`Tags.member.${s+1}.Key`]=a,n[`Tags.member.${s+1}.Value`]=c;let r=await this.request("UpdateStack",n);return(r?.UpdateStackResult||r?.UpdateStackResponse?.UpdateStackResult||r)?.StackId}async deleteStack(e){await this.request("DeleteStack",{StackName:e})}async describeStack(e){let n=await this.request("DescribeStacks",{StackName:e}),i=(n?.DescribeStacksResult||n?.DescribeStacksResponse?.DescribeStacksResult||n)?.Stacks?.member,s=Array.isArray(i)?i[0]:i;if(!s)throw Error(`Stack ${e} not found`);return Ti(s)}async listStacks(e){let n={};if(e)for(let[i,s]of e.entries())n[`StackStatusFilter.member.${i+1}`]=s;let r=await this.request("ListStacks",n);return Ri(r)}async describeStackEvents(e){let n=await this.request("DescribeStackEvents",{StackName:e});return Pi(n)}async waitForStack(e,n,r){let a=0,c=null;while(a<360){a++;let u=await this.describeStack(e);if(r)try{let d=await this.describeStackEvents(e),m=[];if(c){for(let p of d){if(p.EventId===c)break;m.push(p)}m.reverse()}else if(d.length>0)m=[d[0]];for(let p of m)r(p);if(d.length>0)c=d[0].EventId}catch{}if(u.StackStatus&&n.includes(u.StackStatus))return u;if(u.StackStatus?.includes("FAILED")||u.StackStatus?.includes("ROLLBACK"))throw Error(`Stack reached failed state: ${u.StackStatus}
|
|
2461
|
-
Reason: ${u.StackStatusReason||"Unknown"}`);await new Promise((d)=>setTimeout(d,5000))}throw Error(`Timeout waiting for stack ${e} to complete`)}async waitForStackWithProgress(e,n,r){let s={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[n];if(!s)throw Error(`Unknown waiter: ${n}`);return this.waitForStack(e,s,r)}async createChangeSet(e){let n={StackName:e.stackName,ChangeSetName:e.changeSetName,ChangeSetType:"UPDATE"};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;if(e.parameters)for(let[i,[s,a]]of Object.entries(e.parameters).entries())n[`Parameters.member.${i+1}.ParameterKey`]=s,n[`Parameters.member.${i+1}.ParameterValue`]=a;if(e.capabilities)for(let[i,s]of e.capabilities.entries())n[`Capabilities.member.${i+1}`]=s;return(await this.request("CreateChangeSet",n)).ChangeSetId}async executeChangeSet(e,n){await this.request("ExecuteChangeSet",{ChangeSetName:e,StackName:n})}async describeStacks(e){let n=typeof e==="string"?e:e.stackName;try{return{Stacks:[await this.describeStack(n)]}}catch{return{Stacks:[]}}}async getStackOutputs(e){let n=await this.request("DescribeStacks",{StackName:e}),i=(n?.DescribeStacksResult||n?.DescribeStacksResponse?.DescribeStacksResult||n)?.Stacks?.member,s=Array.isArray(i)?i[0]:i;if(!s)return{};let a={},c=s.Outputs?.member;if(c){let u=Array.isArray(c)?c:[c];for(let d of u)if(d.OutputKey&&d.OutputValue)a[d.OutputKey]=d.OutputValue}return a}}function Tt(e,n=""){let r={};for(let[i,s]of Object.entries(e)){let a=n?`${n}.${i}`:i;if(Array.isArray(s))s.forEach((c,u)=>{if(typeof c==="object")Object.assign(r,Tt(c,`${a}.${u+1}`));else r[`${a}.${u+1}`]=String(c)});else if(typeof s==="object"&&s!==null)Object.assign(r,Tt(s,a));else if(s!==void 0&&s!==null)r[a]=String(s)}return r}function vi(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function n(s,a,c){let u=1,d=c,m=`<${a}`,p=`</${a}>`;while(d<s.length&&u>0){let g=s.indexOf(m,d),y=s.indexOf(p,d);if(y===-1)return-1;if(g!==-1&&g<y){let f=s[g+m.length];if(f===">"||f===" "||f==="/"){let h=s.indexOf(">",g);if(h!==-1&&s[h-1]==="/")d=h+1;else u++,d=h+1}else d=g+m.length}else{if(u--,u===0)return y;d=y+p.length}}return-1}function r(s,a){while(a<s.length&&/\s/.test(s[a]))a++;if(a>=s.length||s[a]!=="<"){let S=s.indexOf("<",a);if(S===-1)return{value:s.slice(a).trim(),end:s.length};return{value:s.slice(a,S).trim(),end:S}}if(s[a+1]==="/")return{value:void 0,end:a};let c=s.slice(a).match(/^<(\w+)([^>]*?)\/?>/);if(!c)return{value:void 0,end:a+1};let u=c[1];if(c[0].endsWith("/>"))return{value:"",end:a+c[0].length};let m=a+c[0].length,p=`</${u}>`,g=n(s,u,m);if(g===-1)return{value:void 0,end:a+c[0].length};let y=s.slice(m,g).trim();if(!y.includes("<"))return{value:y,end:g+p.length};let f={},h=m;while(h<g){while(h<g&&/\s/.test(s[h]))h++;if(h>=g)break;if(s[h]!=="<"||s[h+1]==="/")break;let S=s.slice(h).match(/^<(\w+)/);if(!S)break;let A=S[1],R=r(s,h);if(R.value===void 0){h++;continue}if(A==="member"||f[A]!==void 0){if(!Array.isArray(f[A]))f[A]=f[A]!==void 0?[f[A]]:[];f[A].push(R.value)}else f[A]=R.value;h=R.end}return{value:f,end:g+p.length}}return r(e,0).value||{}}function Ti(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function Ri(e){let r=(e?.ListStacksResult||e?.ListStacksResponse?.ListStacksResult||e)?.StackSummaries?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((s)=>({StackName:s.StackName||"",StackId:s.StackId,StackStatus:s.StackStatus,CreationTime:s.CreationTime,LastUpdatedTime:s.LastUpdatedTime,StackStatusReason:s.StackStatusReason,Description:s.Description}))}function Pi(e){let r=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((s)=>({StackId:s.StackId||"",EventId:s.EventId||"",StackName:s.StackName||"",LogicalResourceId:s.LogicalResourceId||"",PhysicalResourceId:s.PhysicalResourceId,ResourceType:s.ResourceType||"",Timestamp:s.Timestamp||"",ResourceStatus:s.ResourceStatus||"",ResourceStatusReason:s.ResourceStatusReason}))}var Ei=5242880,Rt=5242880;var wi=5242880;class ka{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 qi(this.credentialOptions)}buildUrl(e,n){let r=n?encodeURIComponent(n).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return n?`${this.endpoint}/${e}/${r}`:`${this.endpoint}/${e}`;let i=new URL(this.endpoint);return i.hostname=`${e}.${i.hostname}`,n?`${i.origin}/${r}`:i.origin}async get(e,n,r={}){let i=await this.getCredentials(),s=this.buildUrl(e,n),a={};if(r.range)a.Range=r.range;if(r.ifModifiedSince)a["If-Modified-Since"]=r.ifModifiedSince.toUTCString();if(r.ifMatch)a["If-Match"]=r.ifMatch;if(r.ifNoneMatch)a["If-None-Match"]=r.ifNoneMatch;let c=new URL(s);if(r.responseContentType)c.searchParams.set("response-content-type",r.responseContentType);if(r.responseContentDisposition)c.searchParams.set("response-content-disposition",r.responseContentDisposition);let u=Z({method:"GET",url:c.toString(),headers:a,...i,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok&&d.status!==304){let m=await d.text();throw new be(`Failed to get object: ${m}`,d.status,e,n)}return d}async getText(e,n,r={}){return(await this.get(e,n,r)).text()}async getJSON(e,n,r={}){return(await this.get(e,n,r)).json()}async getBuffer(e,n,r={}){return(await this.get(e,n,r)).arrayBuffer()}async put(e,n,r,i={}){let s,a;if(typeof r==="string")s=new TextEncoder().encode(r).length,a=r;else if(r instanceof ArrayBuffer)s=r.byteLength,a=r;else if(r instanceof Uint8Array)s=r.byteLength,a=r;else if(r instanceof Blob)s=r.size,a=r;else return this.uploadMultipart(e,n,r,{...i,partSize:Rt});if(s>wi){let c=Ni(a).stream();return this.uploadMultipart(e,n,c,{...i,partSize:Rt})}return this.putSimple(e,n,a,s,i)}async putSimple(e,n,r,i,s){let a=await this.getCredentials(),c=this.buildUrl(e,n),u={"Content-Length":String(i),"Content-Type":s.contentType||Fn(n)};if(s.contentEncoding)u["Content-Encoding"]=s.contentEncoding;if(s.cacheControl)u["Cache-Control"]=s.cacheControl;if(s.contentDisposition)u["Content-Disposition"]=s.contentDisposition;if(s.storageClass)u["x-amz-storage-class"]=s.storageClass;if(s.serverSideEncryption)u["x-amz-server-side-encryption"]=s.serverSideEncryption;if(s.acl)u["x-amz-acl"]=s.acl;if(s.tagging)u["x-amz-tagging"]=s.tagging;if(s.metadata)for(let[y,f]of Object.entries(s.metadata))u[`x-amz-meta-${y.toLowerCase()}`]=f;let d;if(typeof r==="string")d=r;else if(r instanceof Blob)d=await r.text();else d=new TextDecoder().decode(r instanceof ArrayBuffer?new Uint8Array(r):r);let m=Z({method:"PUT",url:c,headers:u,body:d,...a,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:r});if(!p.ok){let y=await p.text();throw new be(`Failed to put object: ${y}`,p.status,e,n)}return{etag:(p.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),s=Z({method:"DELETE",url:i,...r,service:"s3",region:this.region}),a=await fetch(s.url,{method:s.method,headers:s.headers});if(!a.ok&&a.status!==204){let c=await a.text();throw new be(`Failed to delete object: ${c}`,a.status,e,n)}}async deleteMany(e,n){let r=await this.getCredentials(),i=`${this.buildUrl(e)}?delete`,a=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${n.map((h)=>`<Object><Key>${Di(h)}</Key></Object>`).join("")}</Delete>`,c=Z({method:"POST",url:i,headers:{"Content-Type":"application/xml"},body:a,...r,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:a});if(!u.ok){let h=await u.text();throw new be(`Failed to delete objects: ${h}`,u.status,e)}let d=await u.text(),m=[],p=[],g=/<Deleted><Key>([^<]+)<\/Key>/g,y;while((y=g.exec(d))!==null)m.push(y[1]);let f=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((y=f.exec(d))!==null)p.push({key:y[1],error:`${y[2]}: ${y[3]}`});return{deleted:m,errors:p}}async list(e,n={}){let r=await this.getCredentials(),i=new URL(this.buildUrl(e));if(i.searchParams.set("list-type","2"),n.prefix)i.searchParams.set("prefix",n.prefix);if(n.delimiter)i.searchParams.set("delimiter",n.delimiter);if(n.maxKeys)i.searchParams.set("max-keys",String(n.maxKeys));if(n.continuationToken)i.searchParams.set("continuation-token",n.continuationToken);if(n.startAfter)i.searchParams.set("start-after",n.startAfter);let s=Z({method:"GET",url:i.toString(),...r,service:"s3",region:this.region}),a=await fetch(s.url,{method:s.method,headers:s.headers});if(!a.ok){let u=await a.text();throw new be(`Failed to list objects: ${u}`,a.status,e)}let c=await a.text();return Ii(c)}async*listAll(e,n={}){let r;do{let i=await this.list(e,{...n,continuationToken:r});for(let s of i.contents)yield s;r=i.nextContinuationToken}while(r)}async head(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),s=Z({method:"HEAD",url:i,...r,service:"s3",region:this.region}),a=await fetch(s.url,{method:s.method,headers:s.headers});if(a.status===404)return null;if(!a.ok){let u=await a.text();throw new be(`Failed to head object: ${u}`,a.status,e,n)}let c={};return a.headers.forEach((u,d)=>{if(d.toLowerCase().startsWith("x-amz-meta-"))c[d.slice(11)]=u}),{contentLength:Number(a.headers.get("Content-Length")||0),contentType:a.headers.get("Content-Type")||"application/octet-stream",etag:(a.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(a.headers.get("Last-Modified")||0),metadata:c,storageClass:a.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:a.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,n){return await this.head(e,n)!==null}async copy(e,n,r,i,s={}){let a=await this.getCredentials(),c=this.buildUrl(r,i),u={"x-amz-copy-source":`/${e}/${encodeURIComponent(n)}`};if(s.metadataDirective)u["x-amz-metadata-directive"]=s.metadataDirective;if(s.contentType)u["Content-Type"]=s.contentType;if(s.storageClass)u["x-amz-storage-class"]=s.storageClass;if(s.acl)u["x-amz-acl"]=s.acl;if(s.metadata)for(let[f,h]of Object.entries(s.metadata))u[`x-amz-meta-${f.toLowerCase()}`]=h;let d=Z({method:"PUT",url:c,headers:u,...a,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers});if(!m.ok){let f=await m.text();throw new be(`Failed to copy object: ${f}`,m.status,r,i)}let g=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:g?g[1]:""}}async getPresignedUrl(e,n,r={}){let i=await this.getCredentials(),s=this.buildUrl(e,n);return ls({url:s,method:r.method||"GET",expiresIn:r.expiresIn||3600,...i,service:"s3",region:this.region})}async uploadMultipart(e,n,r,i={}){let s=await this.getCredentials(),a=Math.max(i.partSize||Rt,Ei),c,u;if(r instanceof ReadableStream)c=r;else if(r instanceof Blob)c=r.stream(),u=r.size;else{let p=new Blob([r]);c=p.stream(),u=p.size}let{uploadId:d,baseUrl:m}=await this.initiateMultipartUpload(e,n,i);try{let p=await this.uploadParts(e,n,m,d,c,a,s,u,i.concurrency||4,i.onProgress);return await this.completeMultipartUpload(e,n,m,d,p)}catch(p){throw await this.abortMultipartUpload(e,n,d,m).catch(()=>{}),p}}async initiateMultipartUpload(e,n,r){let i=await this.getCredentials(),s=this.buildUrl(e,n),a=`${s}?uploads`,c={"Content-Type":r.contentType||Fn(n)};if(r.storageClass)c["x-amz-storage-class"]=r.storageClass;if(r.serverSideEncryption)c["x-amz-server-side-encryption"]=r.serverSideEncryption;if(r.acl)c["x-amz-acl"]=r.acl;if(r.metadata)for(let[y,f]of Object.entries(r.metadata))c[`x-amz-meta-${y.toLowerCase()}`]=f;let u=Z({method:"POST",url:a,headers:c,...i,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok){let y=await d.text();throw new be(`Failed to initiate multipart upload: ${y}`,d.status,e,n)}let p=(await d.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!p)throw new be("Failed to parse upload ID from response",0,e,n);let g=s;if(d.url)try{let y=new URL(d.url);y.search="",g=y.toString()}catch{}return{uploadId:p[1],baseUrl:g}}async uploadParts(e,n,r,i,s,a,c,u,d,m){let p=[],g=s.getReader(),y=1,f=new Uint8Array(0),h=0,S=u?Math.ceil(u/a):void 0,A=new Map,R=async(C,E)=>{let D=`${r}?partNumber=${E}&uploadId=${encodeURIComponent(i)}`,x={"Content-Length":String(C.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},L=Z({method:"PUT",url:D,headers:x,...c,service:"s3",region:this.region}),B=await fetch(L.url,{method:L.method,headers:L.headers,body:C,redirect:"error"});if(!B.ok){let F=await B.text();throw new be(`Failed to upload part ${E}: ${F}`,B.status,e,n)}let O=(B.headers.get("ETag")||"").replace(/"/g,"");if(!O)throw new be(`Missing ETag for part ${E}`,B.status,e,n);return{partNumber:E,etag:O}},P=async()=>{let C=await Promise.race(A.values());A.delete(C.partNumber),p.push(C)};while(!0){let{done:C,value:E}=await g.read();if(E){let D=new Uint8Array(f.length+E.length);D.set(f),D.set(E,f.length),f=D}while(f.length>=a||C&&f.length>0){let D=f.slice(0,a);f=f.slice(a);let x=y++;if(A.size>=d)await P();if(A.set(x,R(D,x)),h+=D.byteLength,m)m({loaded:h,total:u||h,part:x,totalParts:S||x})}if(C)break}while(A.size>0)await P();return p.sort((C,E)=>C.partNumber-E.partNumber),p}async completeMultipartUpload(e,n,r,i,s){let a=await this.getCredentials(),c=`${r}?uploadId=${encodeURIComponent(i)}`,d=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${s.map((h)=>`<Part><PartNumber>${h.partNumber}</PartNumber><ETag>"${h.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,m=Z({method:"POST",url:c,headers:{"Content-Type":"application/xml"},body:d,...a,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:d});if(!p.ok){let h=await p.text();throw new be(`Failed to complete multipart upload: ${h}`,p.status,e,n)}let y=(await p.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:y?y[1]:""}}async abortMultipartUpload(e,n,r,i){let s=await this.getCredentials(),a=`${i??this.buildUrl(e,n)}?uploadId=${encodeURIComponent(r)}`,c=Z({method:"DELETE",url:a,...s,service:"s3",region:this.region});await fetch(c.url,{method:c.method,headers:c.headers})}async emptyAndDeleteBucket(e){let r=[];for await(let c of this.listAll(e,{}))if(r.push(c.key),r.length>=1000)await this.deleteMany(e,r),r=[];if(r.length>0)await this.deleteMany(e,r);let i=await this.getCredentials(),s=this.buildUrl(e),a=Z({method:"DELETE",url:s,...i,service:"s3",region:this.region});await fetch(a.url,{method:a.method,headers:a.headers})}}class be extends Error{statusCode;bucket;key;constructor(e,n,r,i){super(e);this.statusCode=n;this.bucket=r;this.key=i;this.name="S3Error"}}function Ii(e){let n=[],r=[],i=/<Contents>([\s\S]*?)<\/Contents>/g,s;while((s=i.exec(e))!==null){let c=s[1];n.push({key:Q(c,"Key")||"",lastModified:new Date(Q(c,"LastModified")||0),etag:(Q(c,"ETag")||"").replace(/"/g,""),size:Number(Q(c,"Size")||0),storageClass:Q(c,"StorageClass")||"STANDARD"})}let a=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((s=a.exec(e))!==null)r.push(s[1]);return{contents:n,commonPrefixes:r,isTruncated:Q(e,"IsTruncated")==="true",continuationToken:Q(e,"ContinuationToken")||void 0,nextContinuationToken:Q(e,"NextContinuationToken")||void 0,keyCount:Number(Q(e,"KeyCount")||0),maxKeys:Number(Q(e,"MaxKeys")||1000),prefix:Q(e,"Prefix")||void 0,delimiter:Q(e,"Delimiter")||void 0}}function Q(e,n){let r=new RegExp(`<${n}>([^<]*)</${n}>`),i=e.match(r);return i?i[1]:null}function Di(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function Fn(e){let n=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"}[n||""]||"application/octet-stream"}function Ni(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function ku(e){return new ka(e)}class Nu{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await Dn(this.profile)}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async createInvalidation(e){let n=await this.ensureCredentials(),r=e.callerReference||`invalidation-${Date.now()}`,i=`<?xml version="1.0" encoding="UTF-8"?>
|
|
2458
|
+
`}},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:[i||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${r}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:i?{domain:i,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:u==="mysql"?{mysql:{engine:"mysql",version:"8.0",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",innodb_buffer_pool_size:"{DBInstanceClassMemory*3/4}",slow_query_log:"1",long_query_time:"2"}}}:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",shared_buffers:"{DBInstanceClassMemory/4}",log_min_duration_statement:"2000"}}},cache:d==="redis"?{redis:{nodeType:"cache.t3.medium",numCacheNodes:2,engine:"redis",engineVersion:"7.0",port:6379,parameterGroup:{maxmemoryPolicy:"allkeys-lru",timeout:"300"},snapshotRetentionLimit:5,snapshotWindow:"03:00-05:00",automaticFailoverEnabled:!0}}:void 0,queues:{jobs:{fifo:!1,visibilityTimeout:900,messageRetentionPeriod:345600,receiveMessageWaitTime:20,deadLetterQueue:!0,maxReceiveCount:3},emails:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:86400,deadLetterQueue:!0}},functions:{"job-worker":{runtime:"nodejs20.x",handler:"dist/workers/jobs.handler",memory:2048,timeout:900,events:[{type:"sqs",queueName:`${r}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${r}-emails`,batchSize:10}]},cleanup:{runtime:"nodejs20.x",handler:"dist/tasks/cleanup.handler",memory:512,timeout:300,events:[{type:"schedule",expression:"cron(0 2 * * ? *)"}]}},monitoring:{dashboard:{name:`${r}-web-app`,widgets:[{type:"metric",metrics:["EC2CPUUtilization","ALBRequestCount","ALBTargetResponseTime","RDSCPUUtilization","RDSDatabaseConnections","RDSReadLatency","RDSWriteLatency"]}]},alarms:[{metric:"EC2CPUUtilization",threshold:80,evaluationPeriods:2},{metric:"RDSCPUUtilization",threshold:80,evaluationPeriods:2},{metric:"RDSDatabaseConnections",threshold:400,evaluationPeriods:1},{metric:"ALBTargetResponseTime",threshold:2000,evaluationPeriods:2},{metric:"ALBUnhealthyHostCount",threshold:1,evaluationPeriods:1}],logs:{retention:14,groups:[`${r}-app`,`${r}-nginx`,`${r}-workers`]}},security:{certificate:i?{domain:i,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","knownBadInputs"]},securityGroups:{alb:{ingress:[{port:80,protocol:"tcp",cidr:"0.0.0.0/0"},{port:443,protocol:"tcp",cidr:"0.0.0.0/0"}]},app:{ingress:[{port:3000,protocol:"tcp",source:"alb-sg"}]},database:{ingress:[{port:u==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...d==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function og(e){let{name:n,slug:r,domain:i,repository:s,phpVersion:a="8.3",size:c="small",database:u=r.replace(/-/g,"_"),databasePassword:d,sslEmail:m,deployStrategy:p="push",provider:g="hetzner"}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"server",cloud:{provider:g},environments:{production:{type:"production",domain:i}},infrastructure:{compute:{mode:"server",size:c,runtime:"php",webServer:"nginx",php:{versions:[a],default:a},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:u,username:u,password:d}},sites:{main:{root:".",type:"laravel",domain:i,phpVersion:a,repository:{...s,strategy:p},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:m}}}}}function sg(e){let{name:n,slug:r,domain:i,layers:s,phpVersion:a="8.3",architecture:c="x86_64",memory:u=1024,build:d,deploy:m=["migrate --force"],cache:p="dynamodb",scheduler:g="on",region:y="us-east-1"}=e;return{project:{name:n,slug:r,region:y},mode:"serverless",environments:{production:{type:"production",domain:i,app:{kind:"php",runtime:"provided.al2023",phpVersion:a,architecture:c,layers:s,memory:u,build:d,deploy:m,assets:"public",queues:!0,scheduler:g,cache:{driver:p},domain:i}}}}}function ag(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 Ru=Sa,Iu="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function Bi(e){let n=e.split(".").filter(Boolean);return n.length<=2?e:n.slice(-2).join(".")}function Fi(e){let n=2166136261;for(let r=0;r<e.length;r++)n^=e.charCodeAt(r),n=Math.imul(n,16777619);return n>>>0}var Pu=20000,Du=12000;function ku(e){return Pu+Fi(e)%Du}function Bn(e,n){let r=Bi(e);if(r===e)return`dashboard.${r}`;for(let i of n)if(i===r)return`dashboard.${r}`;return`dashboard.${e}`}function Fn(e,n){let r=[],i=e.infrastructure?.dns?.domain;if(i&&!e.cloud?.attachTo)r.push(i);if(n&&e.environments?.[n]?.domain)r.push(e.environments[n].domain);for(let s of Object.values(e.sites??{})){let a=s;if(!a||a.redirect)continue;let c=a.domain;if(typeof c==="string")r.push(c);else if(Array.isArray(c))r.push(...c.filter((u)=>typeof u==="string"))}return r.filter((s)=>s&&!s.startsWith("dashboard."))}function Nu(e,n,r){if(r)return r;let i=Fn(e,n),s=i[0];if(!s)return null;return Bn(s,i)}function xu(e,n,r){if(r)return[r];let i=Fn(e,n),s=[];for(let a of i){let c=Bn(a,i);if(!s.includes(c))s.push(c)}return s}function rr(e){return Object.entries(e.sites??{}).some(([n,r])=>{if(!r)return!1;let i=r.root??"";return Hr(n)||i==="ui/dist"||i.endsWith("/ui/dist")||i.endsWith("/dist/ui")})}var Al="dashboard-";function Rl(e){return Al+e.replace(/^dashboard\./,"").replace(/\./g,"-")}function Hr(e){return e==="dashboard"||e.startsWith(Al)}function Wi(e,n,r){if(rr(e))return[];if(e.cloud?.attachTo)return[];let i=r.password?{auth:{username:r.username||"admin",password:r.password,realm:r.realm}}:{},s=r.build===!1||r.build===void 0?{}:{build:r.build};if(r.live!==!1){let c=Nu(e,n,r.domain);if(!c)return[];let u=r.port??ku(c),d=e.infrastructure?.appDatabase??e.infrastructure?.compute?.database,m={root:r.uiRoot,deploy:"server",domain:c,preStart:["bun install --production --no-save"],start:`bun ${Iu} --box --host 127.0.0.1 --port ${u}`,port:u,cpuWeight:10,ioWeight:10,tasksMax:128,env:{APP_ENV:"production",NODE_ENV:"production",TS_CLOUD_DASHBOARD_TELEMETRY:"1",...d?.password?{TS_CLOUD_DASHBOARD_DB_PASSWORD:d.password}:{}},zeroDowntime:!1,sharedPaths:[Ru],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:Rl(c),site:m}]}return xu(e,n,r.domain).map((c)=>({name:Rl(c),site:{root:r.uiRoot,deploy:"server",type:"static",domain:c,ssl:{provider:"letsencrypt"},...s,...i}}))}function cg(e,n,r){return Wi(e,n,r)[0]??null}function Rt(e,n){let r={...e};for(let i in n){let s=n[i],a=r[i];if(s===void 0)continue;if(Array.isArray(s)&&Array.isArray(a))r[i]=[...a,...s];else if(typeof s==="object"&&s!==null&&!Array.isArray(s)&&typeof a==="object"&&a!==null&&!Array.isArray(a))r[i]=Rt(a,s);else r[i]=s}return r}function Il(e,n){return Rt(e,n)}function lg(...e){return e.reduce((n,r)=>Rt(n,r),{})}function dg(e,n){return(r)=>{let i=e(r);if(typeof n==="function")return Il(i,n(i,r));return Il(i,n)}}function Dn(e){return{infrastructure:e}}function ug(e){return Dn({monitoring:e})}function pg(e){return Dn({security:e})}function mg(e){return Dn({databases:e})}function gg(e){return Dn({cache:e})}function fg(e){return Dn({cdn:e})}function hg(e){return Dn({queues:e})}import{readFileSync as Ts}from"node:fs";import{spawn as _i,spawnSync as Ui}from"node:child_process";import{existsSync as ji,readFileSync as es}from"node:fs";import{homedir as Pt}from"node:os";import{join as Et}from"node:path";var Pl=30000,bs=300000,Vn=1048576;class Z extends Error{code="CredentialProcessError";profile;command;constructor(e,n,r){super(`AWS profile "${e}": credential_process \`${n}\` ${r}`);this.name="CredentialProcessError",this.profile=e,this.command=n}}function Un(e){return e==="~"||e.startsWith("~/")?Et(Pt(),e.slice(1)):e}function Ke(e){return e||process.env.AWS_PROFILE||process.env.AWS_DEFAULT_PROFILE||"default"}function Ki(e){return Un(e||process.env.AWS_SHARED_CREDENTIALS_FILE||Et(Pt(),".aws","credentials"))}function ls(e){return Un(e||process.env.AWS_CONFIG_FILE||Et(Pt(),".aws","config"))}function Ss(e){let n=new Map,r=null;for(let i of e.replace(/^/,"").split(/\r?\n/)){let s=i.trim();if(!s||s.startsWith("#")||s.startsWith(";"))continue;let a=s.match(/^\[([^\]]+)\]/);if(a){let u=a[1].trim();r=n.get(u)??{},n.set(u,r);continue}let c=s.indexOf("=");if(r&&c>0)r[s.slice(0,c).trim().toLowerCase()]=s.slice(c+1).trim()}return n}function Gn(e){if(!ji(e))return new Map;try{return Ss(es(e,"utf-8"))}catch{return new Map}}function As(e,n){if(n==="default")return e.get("default")??e.get("profile default");for(let[r,i]of e){let s=r.match(/^profile\s+(.+)$/);if(s&&s[1].trim()===n)return i}return}function kn(e){let n=Ke(e?.profile),r=As(Gn(ls(e?.configFile)),n),i=Gn(Ki(e?.credentialsFile)).get(n);if(!r&&!i)return;return{...r,...i}}function wt(e){let n=e?.aws_access_key_id,r=e?.aws_secret_access_key;if(!n||!r)return null;return{accessKeyId:n,secretAccessKey:r,sessionToken:e?.aws_session_token||void 0}}function Ji(e){return wt(kn(e))}function ds(e){return kn(e)?.credential_process||null}function _u(e,n=process.platform){let r=[],i="",s=!1,a=null;for(let c=0;c<e.length;c++){let u=e[c];if(a==="'"){if(u==="'")a=null;else i+=u;continue}if(a==='"'){if(u==='"')a=null;else if(u==="\\"&&(e[c+1]==='"'||e[c+1]==="\\"||n!=="win32"&&(e[c+1]==="$"||e[c+1]==="`")))i+=e[++c];else i+=u;continue}if(u==="'"||u==='"')a=u,s=!0;else if(u==="\\"&&n!=="win32"&&c+1<e.length)i+=e[++c],s=!0;else if(/\s/.test(u)){if(s)r.push(i),i="",s=!1}else i+=u,s=!0}if(a)throw Error("unterminated quote");if(s)r.push(i);return r}function Hn(e){let n=e.replace(/\s+/g," ").trim();return n.length>200?`${n.slice(0,200)}...`:n}function jn(e,n,r){let i;try{i=JSON.parse(e)}catch{throw new Z(n,r,"printed output that is not valid JSON")}if(!i||typeof i!=="object"||Array.isArray(i))throw new Z(n,r,"printed JSON that is not an object");let s=i;if(s.Version!==1)throw new Z(n,r,'printed JSON without "Version": 1');let{AccessKeyId:a,SecretAccessKey:c,SessionToken:u,Expiration:d}=s;if(typeof a!=="string"||!a||typeof c!=="string"||!c)throw new Z(n,r,"printed JSON without AccessKeyId and SecretAccessKey");if(u!==void 0&&u!==null&&typeof u!=="string")throw new Z(n,r,"printed a SessionToken that is not a string");let m;if(d!==void 0&&d!==null){if(m=typeof d==="string"?new Date(d):void 0,!m||Number.isNaN(m.getTime()))throw new Z(n,r,"printed an Expiration that is not a date")}return{accessKeyId:a,secretAccessKey:c,sessionToken:typeof u==="string"&&u?u:void 0,expiration:m}}function Kn(e){return e>=1000&&e%1000===0?`${e/1000}s`:`${e}ms`}function qn(e,n){let r;try{r=_u(n)}catch(i){throw new Z(e,n,`could not be parsed (${i.message})`)}if(r.length===0)throw new Z(e,n,"is empty");return r}function Wn(e,n){try{if(e&&process.platform!=="win32")process.kill(-e,"SIGKILL");else n()}catch{try{n()}catch{}}}function Cs(e,n,r){let i=qn(e,n);return new Promise((s,a)=>{let c=!1,u=[],d=0,m="",p=_i(i[0],i.slice(1),{stdio:["ignore","pipe","pipe"],detached:process.platform!=="win32",windowsHide:!0}),g=(f)=>{if(c)return;c=!0,clearTimeout(y),p.stdout?.destroy(),p.stderr?.destroy(),f()},y=setTimeout(()=>{Wn(p.pid,()=>p.kill("SIGKILL")),g(()=>a(new Z(e,n,`timed out after ${Kn(r)} and was killed`)))},r);p.on("error",(f)=>{g(()=>a(new Z(e,n,`could not be started (${f.code??"spawn error"})`)))}),p.stdout?.on("data",(f)=>{if(d+=f.length,d>Vn){Wn(p.pid,()=>p.kill("SIGKILL")),g(()=>a(new Z(e,n,"printed more than 1 MiB")));return}u.push(f)}),p.stderr?.on("data",(f)=>{if(m.length<2000)m+=f.toString("utf-8")}),p.on("close",(f,h)=>{g(()=>{if(f!==0){let S=Hn(m),A=f===null?`was stopped by ${h}`:`exited with code ${f}`;a(new Z(e,n,S?`${A}: ${S}`:A));return}s(Buffer.concat(u).toString("utf-8"))})})})}function vs(e,n,r){let i=qn(e,n),s=Ui(i[0],i.slice(1),{stdio:["ignore","pipe","pipe"],timeout:r,killSignal:"SIGKILL",maxBuffer:Vn,windowsHide:!0}),a=s.error?.code;if(a==="ETIMEDOUT")throw new Z(e,n,`timed out after ${Kn(r)} and was killed`);if(a==="ENOBUFS")throw new Z(e,n,"printed more than 1 MiB");if(s.error)throw new Z(e,n,`could not be started (${a??"spawn error"})`);if(s.status!==0){let c=Hn(s.stderr?.toString("utf-8")??""),u=s.status===null?`was stopped by ${s.signal}`:`exited with code ${s.status}`;throw new Z(e,n,c?`${u}: ${c}`:u)}return s.stdout.toString("utf-8")}var It=new Map,it=new Map;function zn(e,n){return`${e}\x00${n}`}function Qn(e){let n=It.get(e);return n&&Date.now()<n.refreshAt?n.credentials:null}function Jn(e,n){It.set(e,{credentials:n,refreshAt:n.expiration?n.expiration.getTime()-bs:Number.POSITIVE_INFINITY})}function yg(){It.clear(),it.clear()}async function Xi(e){let n=Ke(e?.profile),r=kn({...e,profile:n}),i=wt(r);if(i)return i;let s=r?.credential_process;if(!s)return null;let a=zn(n,s),c=Qn(a);if(c)return c;let u=it.get(a);if(u)return u;let d=Cs(n,s,e?.timeoutMs??Pl).then((m)=>{let p=jn(m,n,s);return Jn(a,p),p}).finally(()=>{it.delete(a)});return it.set(a,d),d}function us(e){let n=Ke(e?.profile),r=kn({...e,profile:n}),i=wt(r);if(i)return i;let s=r?.credential_process;if(!s)return null;let a=zn(n,s),c=Qn(a);if(c)return c;let u=jn(vs(n,s,e?.timeoutMs??Pl),n,s);return Jn(a,u),u}function Ou(){let e=process.env.AWS_ACCESS_KEY_ID,n=process.env.AWS_SECRET_ACCESS_KEY;if(!e||!n)return null;return{accessKeyId:e,secretAccessKey:n,sessionToken:process.env.AWS_SESSION_TOKEN}}function $u(e){let n=Ji({profile:e?.profile,credentialsFile:e?.credentialsFile,configFile:e?.configFile});return n?{accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,sessionToken:n.sessionToken}:null}async function Lu(e){return Xi({profile:e?.profile,credentialsFile:e?.credentialsFile,configFile:e?.configFile})}async function Mu(e){let n=e?.timeout??1000,r="http://169.254.169.254";try{let i=await Qe("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},n);if(!i.ok)return null;let s=await i.text(),a=await Qe("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":s}},n);if(!a.ok)return null;let c=(await a.text()).trim(),u=await Qe(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${c}`,{headers:{"X-aws-ec2-metadata-token":s}},n);if(!u.ok)return null;let d=await u.json();return{accessKeyId:d.AccessKeyId,secretAccessKey:d.SecretAccessKey,sessionToken:d.Token,expiration:new Date(d.Expiration)}}catch{return null}}async function Uu(e){let n=e?.timeout??1000,r=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,i=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,s=null;if(r)s=`http://169.254.170.2${r}`;else if(i)s=i;if(!s)return null;try{let a={},c=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(c)a.Authorization=c;let u=await Qe(s,{headers:a},n);if(!u.ok)return null;let d=await u.json();return{accessKeyId:d.AccessKeyId,secretAccessKey:d.SecretAccessKey,sessionToken:d.Token,expiration:new Date(d.Expiration)}}catch{return null}}async function Bu(e){let n=e?.timeout??5000,r=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,i=process.env.AWS_ROLE_ARN,s=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!r||!i)return null;try{let a=Ts(r,"utf-8").trim(),c=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION||"us-east-1",u=c.startsWith("us-gov")?`https://sts.${c}.amazonaws.com`:c==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${c}.amazonaws.com`,d=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:i,RoleSessionName:s,WebIdentityToken:a}),m=await Qe(`${u}/?${d.toString()}`,{method:"POST"},n);if(!m.ok)return null;let p=await m.text(),g=ze(p,"AccessKeyId"),y=ze(p,"SecretAccessKey"),f=ze(p,"SessionToken"),h=ze(p,"Expiration");if(!g||!y)return null;return{accessKeyId:g,secretAccessKey:y,sessionToken:f??void 0,expiration:h?new Date(h):void 0}}catch{return null}}async function Qi(e){let n=Ou();if(n)return n;let r=$u(e);if(r)return r;let i=await Lu(e);if(i)return i;let s=await Bu(e);if(s)return s;let a=await Uu(e);if(a)return a;let c=await Mu(e);if(c)return c;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 bg(e){let n=null,r=null;return async()=>{if(n){if(!n.expiration)return n;let i=300000;if(n.expiration.getTime()-Date.now()>i)return n}if(r)return r;return r=Qi(e).then((i)=>(n=i,r=null,i)).catch((i)=>{throw r=null,i}),r}}async function Qe(e,n,r){let i=new AbortController,s=setTimeout(()=>i.abort(),r);try{let a=await fetch(e,{...n,signal:i.signal});return clearTimeout(s),a}catch(a){throw clearTimeout(s),a}}function ze(e,n){let r=new RegExp(`<${n}>([^<]+)</${n}>`),i=e.match(r);return i?i[1]:null}async function Nn(e){return Qi({profile:e})}function Fu(e){let n=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(n)return n;let r=kn({profile:e})?.region;if(r)return r;return"us-east-1"}async function Dl(e){let n=e||await Qi(),r=Fu(),{signRequest:i}=await import("./chunk-qd1jfsam.js"),s=r.startsWith("us-gov")?`https://sts.${r}.amazonaws.com`:r==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${r}.amazonaws.com`,a="Action=GetCallerIdentity&Version=2011-06-15",c=i({method:"POST",url:s,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...n,service:"sts",region:r}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:c.body});if(!u.ok)throw Error(`Failed to get account ID: ${await u.text()}`);let d=await u.text(),m=ze(d,"Account");if(!m)throw Error("Failed to parse account ID from response");return m}class ju{profile;credentials=null;region;constructor(e="us-east-1",n="default"){this.profile=n;this.region=e}async init(){if(this.credentials=await Nn(this.profile),this.credentials.region)this.region=this.credentials.region}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async request(e,n){let r=await this.ensureCredentials(),i={Action:e,Version:"2010-05-15",...Dt(n)},s=new URLSearchParams(i).toString(),c=await(await Lt({method:"POST",url:`https://cloudformation.${this.region}.amazonaws.com/`,service:"cloudformation",region:this.region,headers:{"Content-Type":"application/x-www-form-urlencoded"},body:s,accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken})).text();return Rs(c)}async createStack(e){let n={StackName:e.stackName};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;else throw Error("Either templateBody or templateURL must be provided");if(e.parameters)for(let[s,[a,c]]of Object.entries(e.parameters).entries())n[`Parameters.member.${s+1}.ParameterKey`]=a,n[`Parameters.member.${s+1}.ParameterValue`]=c;if(e.capabilities)for(let[s,a]of e.capabilities.entries())n[`Capabilities.member.${s+1}`]=a;if(e.tags)for(let[s,[a,c]]of Object.entries(e.tags).entries())n[`Tags.member.${s+1}.Key`]=a,n[`Tags.member.${s+1}.Value`]=c;if(e.timeoutInMinutes)n.TimeoutInMinutes=e.timeoutInMinutes;if(e.onFailure)n.OnFailure=e.onFailure;let r=await this.request("CreateStack",n);return(r?.CreateStackResult||r?.CreateStackResponse?.CreateStackResult||r)?.StackId}async updateStack(e){let n={StackName:e.stackName};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;if(e.parameters)for(let[s,[a,c]]of Object.entries(e.parameters).entries())n[`Parameters.member.${s+1}.ParameterKey`]=a,n[`Parameters.member.${s+1}.ParameterValue`]=c;if(e.capabilities)for(let[s,a]of e.capabilities.entries())n[`Capabilities.member.${s+1}`]=a;if(e.tags)for(let[s,[a,c]]of Object.entries(e.tags).entries())n[`Tags.member.${s+1}.Key`]=a,n[`Tags.member.${s+1}.Value`]=c;let r=await this.request("UpdateStack",n);return(r?.UpdateStackResult||r?.UpdateStackResponse?.UpdateStackResult||r)?.StackId}async deleteStack(e){await this.request("DeleteStack",{StackName:e})}async describeStack(e){let n=await this.request("DescribeStacks",{StackName:e}),i=(n?.DescribeStacksResult||n?.DescribeStacksResponse?.DescribeStacksResult||n)?.Stacks?.member,s=Array.isArray(i)?i[0]:i;if(!s)throw Error(`Stack ${e} not found`);return Ps(s)}async listStacks(e){let n={};if(e)for(let[i,s]of e.entries())n[`StackStatusFilter.member.${i+1}`]=s;let r=await this.request("ListStacks",n);return Es(r)}async describeStackEvents(e){let n=await this.request("DescribeStackEvents",{StackName:e});return ws(n)}async waitForStack(e,n,r){let a=0,c=null;while(a<360){a++;let u=await this.describeStack(e);if(r)try{let d=await this.describeStackEvents(e),m=[];if(c){for(let p of d){if(p.EventId===c)break;m.push(p)}m.reverse()}else if(d.length>0)m=[d[0]];for(let p of m)r(p);if(d.length>0)c=d[0].EventId}catch{}if(u.StackStatus&&n.includes(u.StackStatus))return u;if(u.StackStatus?.includes("FAILED")||u.StackStatus?.includes("ROLLBACK"))throw Error(`Stack reached failed state: ${u.StackStatus}
|
|
2459
|
+
Reason: ${u.StackStatusReason||"Unknown"}`);await new Promise((d)=>setTimeout(d,5000))}throw Error(`Timeout waiting for stack ${e} to complete`)}async waitForStackWithProgress(e,n,r){let s={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[n];if(!s)throw Error(`Unknown waiter: ${n}`);return this.waitForStack(e,s,r)}async createChangeSet(e){let n={StackName:e.stackName,ChangeSetName:e.changeSetName,ChangeSetType:"UPDATE"};if(e.templateBody)n.TemplateBody=e.templateBody;else if(e.templateURL)n.TemplateURL=e.templateURL;if(e.parameters)for(let[i,[s,a]]of Object.entries(e.parameters).entries())n[`Parameters.member.${i+1}.ParameterKey`]=s,n[`Parameters.member.${i+1}.ParameterValue`]=a;if(e.capabilities)for(let[i,s]of e.capabilities.entries())n[`Capabilities.member.${i+1}`]=s;return(await this.request("CreateChangeSet",n)).ChangeSetId}async executeChangeSet(e,n){await this.request("ExecuteChangeSet",{ChangeSetName:e,StackName:n})}async describeStacks(e){let n=typeof e==="string"?e:e.stackName;try{return{Stacks:[await this.describeStack(n)]}}catch{return{Stacks:[]}}}async getStackOutputs(e){let n=await this.request("DescribeStacks",{StackName:e}),i=(n?.DescribeStacksResult||n?.DescribeStacksResponse?.DescribeStacksResult||n)?.Stacks?.member,s=Array.isArray(i)?i[0]:i;if(!s)return{};let a={},c=s.Outputs?.member;if(c){let u=Array.isArray(c)?c:[c];for(let d of u)if(d.OutputKey&&d.OutputValue)a[d.OutputKey]=d.OutputValue}return a}}function Dt(e,n=""){let r={};for(let[i,s]of Object.entries(e)){let a=n?`${n}.${i}`:i;if(Array.isArray(s))s.forEach((c,u)=>{if(typeof c==="object")Object.assign(r,Dt(c,`${a}.${u+1}`));else r[`${a}.${u+1}`]=String(c)});else if(typeof s==="object"&&s!==null)Object.assign(r,Dt(s,a));else if(s!==void 0&&s!==null)r[a]=String(s)}return r}function Rs(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function n(s,a,c){let u=1,d=c,m=`<${a}`,p=`</${a}>`;while(d<s.length&&u>0){let g=s.indexOf(m,d),y=s.indexOf(p,d);if(y===-1)return-1;if(g!==-1&&g<y){let f=s[g+m.length];if(f===">"||f===" "||f==="/"){let h=s.indexOf(">",g);if(h!==-1&&s[h-1]==="/")d=h+1;else u++,d=h+1}else d=g+m.length}else{if(u--,u===0)return y;d=y+p.length}}return-1}function r(s,a){while(a<s.length&&/\s/.test(s[a]))a++;if(a>=s.length||s[a]!=="<"){let S=s.indexOf("<",a);if(S===-1)return{value:s.slice(a).trim(),end:s.length};return{value:s.slice(a,S).trim(),end:S}}if(s[a+1]==="/")return{value:void 0,end:a};let c=s.slice(a).match(/^<(\w+)([^>]*?)\/?>/);if(!c)return{value:void 0,end:a+1};let u=c[1];if(c[0].endsWith("/>"))return{value:"",end:a+c[0].length};let m=a+c[0].length,p=`</${u}>`,g=n(s,u,m);if(g===-1)return{value:void 0,end:a+c[0].length};let y=s.slice(m,g).trim();if(!y.includes("<"))return{value:y,end:g+p.length};let f={},h=m;while(h<g){while(h<g&&/\s/.test(s[h]))h++;if(h>=g)break;if(s[h]!=="<"||s[h+1]==="/")break;let S=s.slice(h).match(/^<(\w+)/);if(!S)break;let A=S[1],R=r(s,h);if(R.value===void 0){h++;continue}if(A==="member"||f[A]!==void 0){if(!Array.isArray(f[A]))f[A]=f[A]!==void 0?[f[A]]:[];f[A].push(R.value)}else f[A]=R.value;h=R.end}return{value:f,end:g+p.length}}return r(e,0).value||{}}function Ps(e){return{StackName:e.StackName||"",StackId:e.StackId,StackStatus:e.StackStatus,CreationTime:e.CreationTime,LastUpdatedTime:e.LastUpdatedTime,StackStatusReason:e.StackStatusReason,Description:e.Description}}function Es(e){let r=(e?.ListStacksResult||e?.ListStacksResponse?.ListStacksResult||e)?.StackSummaries?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((s)=>({StackName:s.StackName||"",StackId:s.StackId,StackStatus:s.StackStatus,CreationTime:s.CreationTime,LastUpdatedTime:s.LastUpdatedTime,StackStatusReason:s.StackStatusReason,Description:s.Description}))}function ws(e){let r=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((s)=>({StackId:s.StackId||"",EventId:s.EventId||"",StackName:s.StackName||"",LogicalResourceId:s.LogicalResourceId||"",PhysicalResourceId:s.PhysicalResourceId,ResourceType:s.ResourceType||"",Timestamp:s.Timestamp||"",ResourceStatus:s.ResourceStatus||"",ResourceStatusReason:s.ResourceStatusReason}))}var Is=5242880,kt=5242880;var Ds=5242880;class Ua{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 Qi(this.credentialOptions)}buildUrl(e,n){let r=n?encodeURIComponent(n).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return n?`${this.endpoint}/${e}/${r}`:`${this.endpoint}/${e}`;let i=new URL(this.endpoint);return i.hostname=`${e}.${i.hostname}`,n?`${i.origin}/${r}`:i.origin}async get(e,n,r={}){let i=await this.getCredentials(),s=this.buildUrl(e,n),a={};if(r.range)a.Range=r.range;if(r.ifModifiedSince)a["If-Modified-Since"]=r.ifModifiedSince.toUTCString();if(r.ifMatch)a["If-Match"]=r.ifMatch;if(r.ifNoneMatch)a["If-None-Match"]=r.ifNoneMatch;let c=new URL(s);if(r.responseContentType)c.searchParams.set("response-content-type",r.responseContentType);if(r.responseContentDisposition)c.searchParams.set("response-content-disposition",r.responseContentDisposition);let u=ee({method:"GET",url:c.toString(),headers:a,...i,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok&&d.status!==304){let m=await d.text();throw new Se(`Failed to get object: ${m}`,d.status,e,n)}return d}async getText(e,n,r={}){return(await this.get(e,n,r)).text()}async getJSON(e,n,r={}){return(await this.get(e,n,r)).json()}async getBuffer(e,n,r={}){return(await this.get(e,n,r)).arrayBuffer()}async put(e,n,r,i={}){let s,a;if(typeof r==="string")s=new TextEncoder().encode(r).length,a=r;else if(r instanceof ArrayBuffer)s=r.byteLength,a=r;else if(r instanceof Uint8Array)s=r.byteLength,a=r;else if(r instanceof Blob)s=r.size,a=r;else return this.uploadMultipart(e,n,r,{...i,partSize:kt});if(s>Ds){let c=ks(a).stream();return this.uploadMultipart(e,n,c,{...i,partSize:kt})}return this.putSimple(e,n,a,s,i)}async putSimple(e,n,r,i,s){let a=await this.getCredentials(),c=this.buildUrl(e,n),u={"Content-Length":String(i),"Content-Type":s.contentType||Yn(n)};if(s.contentEncoding)u["Content-Encoding"]=s.contentEncoding;if(s.cacheControl)u["Cache-Control"]=s.cacheControl;if(s.contentDisposition)u["Content-Disposition"]=s.contentDisposition;if(s.storageClass)u["x-amz-storage-class"]=s.storageClass;if(s.serverSideEncryption)u["x-amz-server-side-encryption"]=s.serverSideEncryption;if(s.acl)u["x-amz-acl"]=s.acl;if(s.tagging)u["x-amz-tagging"]=s.tagging;if(s.metadata)for(let[y,f]of Object.entries(s.metadata))u[`x-amz-meta-${y.toLowerCase()}`]=f;let d;if(typeof r==="string")d=r;else if(r instanceof Blob)d=await r.text();else d=new TextDecoder().decode(r instanceof ArrayBuffer?new Uint8Array(r):r);let m=ee({method:"PUT",url:c,headers:u,body:d,...a,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:r});if(!p.ok){let y=await p.text();throw new Se(`Failed to put object: ${y}`,p.status,e,n)}return{etag:(p.headers.get("ETag")||"").replace(/"/g,"")}}async delete(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),s=ee({method:"DELETE",url:i,...r,service:"s3",region:this.region}),a=await fetch(s.url,{method:s.method,headers:s.headers});if(!a.ok&&a.status!==204){let c=await a.text();throw new Se(`Failed to delete object: ${c}`,a.status,e,n)}}async deleteMany(e,n){let r=await this.getCredentials(),i=`${this.buildUrl(e)}?delete`,a=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${n.map((h)=>`<Object><Key>${xs(h)}</Key></Object>`).join("")}</Delete>`,c=ee({method:"POST",url:i,headers:{"Content-Type":"application/xml"},body:a,...r,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:a});if(!u.ok){let h=await u.text();throw new Se(`Failed to delete objects: ${h}`,u.status,e)}let d=await u.text(),m=[],p=[],g=/<Deleted><Key>([^<]+)<\/Key>/g,y;while((y=g.exec(d))!==null)m.push(y[1]);let f=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((y=f.exec(d))!==null)p.push({key:y[1],error:`${y[2]}: ${y[3]}`});return{deleted:m,errors:p}}async list(e,n={}){let r=await this.getCredentials(),i=new URL(this.buildUrl(e));if(i.searchParams.set("list-type","2"),n.prefix)i.searchParams.set("prefix",n.prefix);if(n.delimiter)i.searchParams.set("delimiter",n.delimiter);if(n.maxKeys)i.searchParams.set("max-keys",String(n.maxKeys));if(n.continuationToken)i.searchParams.set("continuation-token",n.continuationToken);if(n.startAfter)i.searchParams.set("start-after",n.startAfter);let s=ee({method:"GET",url:i.toString(),...r,service:"s3",region:this.region}),a=await fetch(s.url,{method:s.method,headers:s.headers});if(!a.ok){let u=await a.text();throw new Se(`Failed to list objects: ${u}`,a.status,e)}let c=await a.text();return Ns(c)}async*listAll(e,n={}){let r;do{let i=await this.list(e,{...n,continuationToken:r});for(let s of i.contents)yield s;r=i.nextContinuationToken}while(r)}async head(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),s=ee({method:"HEAD",url:i,...r,service:"s3",region:this.region}),a=await fetch(s.url,{method:s.method,headers:s.headers});if(a.status===404)return null;if(!a.ok){let u=await a.text();throw new Se(`Failed to head object: ${u}`,a.status,e,n)}let c={};return a.headers.forEach((u,d)=>{if(d.toLowerCase().startsWith("x-amz-meta-"))c[d.slice(11)]=u}),{contentLength:Number(a.headers.get("Content-Length")||0),contentType:a.headers.get("Content-Type")||"application/octet-stream",etag:(a.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(a.headers.get("Last-Modified")||0),metadata:c,storageClass:a.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:a.headers.get("x-amz-server-side-encryption")||void 0}}async exists(e,n){return await this.head(e,n)!==null}async copy(e,n,r,i,s={}){let a=await this.getCredentials(),c=this.buildUrl(r,i),u={"x-amz-copy-source":`/${e}/${encodeURIComponent(n)}`};if(s.metadataDirective)u["x-amz-metadata-directive"]=s.metadataDirective;if(s.contentType)u["Content-Type"]=s.contentType;if(s.storageClass)u["x-amz-storage-class"]=s.storageClass;if(s.acl)u["x-amz-acl"]=s.acl;if(s.metadata)for(let[f,h]of Object.entries(s.metadata))u[`x-amz-meta-${f.toLowerCase()}`]=h;let d=ee({method:"PUT",url:c,headers:u,...a,service:"s3",region:this.region}),m=await fetch(d.url,{method:d.method,headers:d.headers});if(!m.ok){let f=await m.text();throw new Se(`Failed to copy object: ${f}`,m.status,r,i)}let g=(await m.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:g?g[1]:""}}async getPresignedUrl(e,n,r={}){let i=await this.getCredentials(),s=this.buildUrl(e,n);return ys({url:s,method:r.method||"GET",expiresIn:r.expiresIn||3600,...i,service:"s3",region:this.region})}async uploadMultipart(e,n,r,i={}){let s=await this.getCredentials(),a=Math.max(i.partSize||kt,Is),c,u;if(r instanceof ReadableStream)c=r;else if(r instanceof Blob)c=r.stream(),u=r.size;else{let p=new Blob([r]);c=p.stream(),u=p.size}let{uploadId:d,baseUrl:m}=await this.initiateMultipartUpload(e,n,i);try{let p=await this.uploadParts(e,n,m,d,c,a,s,u,i.concurrency||4,i.onProgress);return await this.completeMultipartUpload(e,n,m,d,p)}catch(p){throw await this.abortMultipartUpload(e,n,d,m).catch(()=>{}),p}}async initiateMultipartUpload(e,n,r){let i=await this.getCredentials(),s=this.buildUrl(e,n),a=`${s}?uploads`,c={"Content-Type":r.contentType||Yn(n)};if(r.storageClass)c["x-amz-storage-class"]=r.storageClass;if(r.serverSideEncryption)c["x-amz-server-side-encryption"]=r.serverSideEncryption;if(r.acl)c["x-amz-acl"]=r.acl;if(r.metadata)for(let[y,f]of Object.entries(r.metadata))c[`x-amz-meta-${y.toLowerCase()}`]=f;let u=ee({method:"POST",url:a,headers:c,...i,service:"s3",region:this.region}),d=await fetch(u.url,{method:u.method,headers:u.headers});if(!d.ok){let y=await d.text();throw new Se(`Failed to initiate multipart upload: ${y}`,d.status,e,n)}let p=(await d.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!p)throw new Se("Failed to parse upload ID from response",0,e,n);let g=s;if(d.url)try{let y=new URL(d.url);y.search="",g=y.toString()}catch{}return{uploadId:p[1],baseUrl:g}}async uploadParts(e,n,r,i,s,a,c,u,d,m){let p=[],g=s.getReader(),y=1,f=new Uint8Array(0),h=0,S=u?Math.ceil(u/a):void 0,A=new Map,R=async(C,E)=>{let D=`${r}?partNumber=${E}&uploadId=${encodeURIComponent(i)}`,x={"Content-Length":String(C.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},L=ee({method:"PUT",url:D,headers:x,...c,service:"s3",region:this.region}),B=await fetch(L.url,{method:L.method,headers:L.headers,body:C,redirect:"error"});if(!B.ok){let F=await B.text();throw new Se(`Failed to upload part ${E}: ${F}`,B.status,e,n)}let O=(B.headers.get("ETag")||"").replace(/"/g,"");if(!O)throw new Se(`Missing ETag for part ${E}`,B.status,e,n);return{partNumber:E,etag:O}},P=async()=>{let C=await Promise.race(A.values());A.delete(C.partNumber),p.push(C)};while(!0){let{done:C,value:E}=await g.read();if(E){let D=new Uint8Array(f.length+E.length);D.set(f),D.set(E,f.length),f=D}while(f.length>=a||C&&f.length>0){let D=f.slice(0,a);f=f.slice(a);let x=y++;if(A.size>=d)await P();if(A.set(x,R(D,x)),h+=D.byteLength,m)m({loaded:h,total:u||h,part:x,totalParts:S||x})}if(C)break}while(A.size>0)await P();return p.sort((C,E)=>C.partNumber-E.partNumber),p}async completeMultipartUpload(e,n,r,i,s){let a=await this.getCredentials(),c=`${r}?uploadId=${encodeURIComponent(i)}`,d=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${s.map((h)=>`<Part><PartNumber>${h.partNumber}</PartNumber><ETag>"${h.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,m=ee({method:"POST",url:c,headers:{"Content-Type":"application/xml"},body:d,...a,service:"s3",region:this.region}),p=await fetch(m.url,{method:m.method,headers:m.headers,body:d});if(!p.ok){let h=await p.text();throw new Se(`Failed to complete multipart upload: ${h}`,p.status,e,n)}let y=(await p.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:y?y[1]:""}}async abortMultipartUpload(e,n,r,i){let s=await this.getCredentials(),a=`${i??this.buildUrl(e,n)}?uploadId=${encodeURIComponent(r)}`,c=ee({method:"DELETE",url:a,...s,service:"s3",region:this.region});await fetch(c.url,{method:c.method,headers:c.headers})}async emptyAndDeleteBucket(e){let r=[];for await(let c of this.listAll(e,{}))if(r.push(c.key),r.length>=1000)await this.deleteMany(e,r),r=[];if(r.length>0)await this.deleteMany(e,r);let i=await this.getCredentials(),s=this.buildUrl(e),a=ee({method:"DELETE",url:s,...i,service:"s3",region:this.region});await fetch(a.url,{method:a.method,headers:a.headers})}}class Se extends Error{statusCode;bucket;key;constructor(e,n,r,i){super(e);this.statusCode=n;this.bucket=r;this.key=i;this.name="S3Error"}}function Ns(e){let n=[],r=[],i=/<Contents>([\s\S]*?)<\/Contents>/g,s;while((s=i.exec(e))!==null){let c=s[1];n.push({key:Q(c,"Key")||"",lastModified:new Date(Q(c,"LastModified")||0),etag:(Q(c,"ETag")||"").replace(/"/g,""),size:Number(Q(c,"Size")||0),storageClass:Q(c,"StorageClass")||"STANDARD"})}let a=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((s=a.exec(e))!==null)r.push(s[1]);return{contents:n,commonPrefixes:r,isTruncated:Q(e,"IsTruncated")==="true",continuationToken:Q(e,"ContinuationToken")||void 0,nextContinuationToken:Q(e,"NextContinuationToken")||void 0,keyCount:Number(Q(e,"KeyCount")||0),maxKeys:Number(Q(e,"MaxKeys")||1000),prefix:Q(e,"Prefix")||void 0,delimiter:Q(e,"Delimiter")||void 0}}function Q(e,n){let r=new RegExp(`<${n}>([^<]*)</${n}>`),i=e.match(r);return i?i[1]:null}function xs(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}function Yn(e){let n=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"}[n||""]||"application/octet-stream"}function ks(e){if(e instanceof Blob)return e;if(typeof e==="string")return new Blob([e],{type:"text/plain"});return new Blob([e])}function Vu(e){return new Ua(e)}class zu{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await Nn(this.profile)}async ensureCredentials(){if(!this.credentials)await this.init();return this.credentials}async createInvalidation(e){let n=await this.ensureCredentials(),r=e.callerReference||`invalidation-${Date.now()}`,i=`<?xml version="1.0" encoding="UTF-8"?>
|
|
2462
2460
|
<InvalidationBatch>
|
|
2463
2461
|
<Paths>
|
|
2464
2462
|
<Quantity>${e.paths.length}</Quantity>
|
|
@@ -2467,24 +2465,24 @@ Reason: ${u.StackStatusReason||"Unknown"}`);await new Promise((d)=>setTimeout(d,
|
|
|
2467
2465
|
</Items>
|
|
2468
2466
|
</Paths>
|
|
2469
2467
|
<CallerReference>${r}</CallerReference>
|
|
2470
|
-
</InvalidationBatch>`,s=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e.distributionId}/invalidation`,a=await
|
|
2468
|
+
</InvalidationBatch>`,s=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e.distributionId}/invalidation`,a=await Lt({method:"POST",url:s,service:"cloudfront",region:"us-east-1",headers:{"Content-Type":"text/xml"},body:i,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,sessionToken:n.sessionToken});return(await On(a)).Id}async getInvalidation(e,n){let r=await this.ensureCredentials(),i=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e}/invalidation/${n}`,s=await Lt({method:"GET",url:i,service:"cloudfront",region:"us-east-1",accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken});return await On(s)}async listInvalidations(e){let n=await this.ensureCredentials(),r=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e}/invalidation`,i=await Lt({method:"GET",url:r,service:"cloudfront",region:"us-east-1",accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,sessionToken:n.sessionToken});return(await On(i)).Items||[]}async waitForInvalidation(e,n,r=60,i=5000){for(let s=0;s<r;s++){if((await this.getInvalidation(e,n)).Status==="Completed")return;if(s<r-1)await new Promise((c)=>setTimeout(c,i))}throw Error(`Invalidation ${n} did not complete within the expected time`)}async invalidateAll(e){return await this.createInvalidation({distributionId:e,paths:["/*"]})}}class Ot extends Error{code;solution;details;constructor(e,n,r,i){super(e);this.code=n;this.solution=r;this.details=i;this.name="CloudError",Error.captureStackTrace?.(this,Ot)}toString(){let e=`${this.name} [${this.code}]: ${this.message}`;if(this.solution)e+=`
|
|
2471
2469
|
|
|
2472
2470
|
\uD83D\uDCA1 Solution: ${this.solution}`;if(this.details&&Object.keys(this.details).length>0){e+=`
|
|
2473
2471
|
|
|
2474
2472
|
Details:`;for(let[n,r]of Object.entries(this.details))e+=`
|
|
2475
|
-
${n}: ${JSON.stringify(r)}`}return e}}class
|
|
2473
|
+
${n}: ${JSON.stringify(r)}`}return e}}class ps extends Ot{constructor(e,n,r){super(e,"CONFIG_ERROR",n,r);this.name="ConfigurationError"}}class nr extends Ot{constructor(e,n,r){super(e,"CREDENTIAL_ERROR",n,r);this.name="CredentialError"}}class Hu extends Ot{constructor(e,n,r){super(e,"DEPLOYMENT_ERROR",n,r);this.name="DeploymentError"}}class kl extends Ot{constructor(e,n,r){super(e,"VALIDATION_ERROR",n,r);this.name="ValidationError"}}class Gu extends Ot{statusCode;constructor(e,n,r,i){super(e,"AWS_API_ERROR",r,i);this.statusCode=n;this.name="AWSAPIError"}}var qu={NO_CREDENTIALS:{message:"AWS credentials not found",solution:`Configure AWS credentials using one of these methods:
|
|
2476
2474
|
1. Set environment variables: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
|
|
2477
2475
|
2. Create ~/.aws/credentials file with your credentials
|
|
2478
2476
|
3. Use an IAM role (for EC2 instances)
|
|
2479
|
-
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
|
|
2480
|
-
Stack trace:`),console.error(n.stack)}}static success(e){console.log(`✔ ${e}`)}}function
|
|
2477
|
+
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 Wu(e){return qu[e]}function Nl(e,n){let r=Wu(e);return new Ot(r.message,e,r.solution,n)}class ve{static verboseMode=!1;static debugMode=!1;static setVerbose(e){this.verboseMode=e}static setDebug(e){this.debugMode=e}static verbose(e,...n){if(this.verboseMode)console.log(`[VERBOSE] ${e}`,...n)}static debug(e,...n){if(this.debugMode)console.log(`[DEBUG] ${e}`,...n)}static info(e,...n){console.log(`ℹ ${e}`,...n)}static warn(e,...n){console.warn(`⚠ ${e}`,...n)}static error(e,n){if(console.error(`✖ ${e}`),n){if(n instanceof Ot)console.error(n.toString());else console.error(n.message);if(this.debugMode&&n.stack)console.error(`
|
|
2478
|
+
Stack trace:`),console.error(n.stack)}}static success(e){console.log(`✔ ${e}`)}}function Sg(e){if(!e)throw Nl("MISSING_CONFIG");if(!e.project)throw new ps("Missing required field: project","Add a project configuration with name, slug, and region",{field:"project"});if(!e.project.name)throw new ps("Missing required field: project.name","Add a project name to your configuration",{field:"project.name"});if(!e.project.slug)throw new ps("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 kl("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 Nl("INVALID_REGION",{region:e.project.region})}ve.success("Configuration validation passed")}function vg(e){let n=[];if(e.environments?.production&&e.infrastructure?.database){let r=e.infrastructure.database;if((r.postgres||r.mysql)&&!r.postgres?.multiAZ&&!r.mysql?.multiAZ)n.push("Production database should use Multi-AZ for high availability")}if(e.infrastructure?.storage){for(let[r,i]of Object.entries(e.infrastructure.storage))if(i.encryption===!1)n.push(`Storage "${r}" is not encrypted - consider enabling encryption for security`)}if(e.infrastructure?.storage){for(let[r,i]of Object.entries(e.infrastructure.storage))if(i.public===!0)n.push(`Storage "${r}" is publicly accessible - ensure this is intentional`)}if(e.infrastructure?.database){let r=e.infrastructure.database;if(r.postgres||r.mysql){let i=r.postgres?.backupRetentionDays||r.mysql?.backupRetentionDays;if(!i||i<7)n.push("Database backup retention is less than 7 days - consider increasing for production")}}if(!e.infrastructure?.monitoring)n.push("No monitoring configured - consider adding CloudWatch alarms");return n}async function Cg(e="default"){try{ve.verbose("Resolving AWS credentials...");let n=await Nn(e);if(!n.accessKeyId||!n.secretAccessKey)throw new nr("AWS credentials are incomplete","Ensure both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are set");ve.verbose("Credentials resolved successfully"),ve.debug("Access Key ID:",n.accessKeyId.substring(0,8)+"..."),ve.verbose("Testing credentials with GetCallerIdentity...");let r;try{r=await Dl(n),ve.verbose("Credentials are valid"),ve.debug("Account ID:",r)}catch(i){if(i instanceof Error)if(i.message.includes("InvalidClientTokenId"))throw new nr("Invalid AWS access key ID","Check that your AWS_ACCESS_KEY_ID is correct");else if(i.message.includes("SignatureDoesNotMatch"))throw new nr("Invalid AWS secret access key","Check that your AWS_SECRET_ACCESS_KEY is correct");else if(i.message.includes("ExpiredToken"))throw new nr("AWS credentials have expired","Refresh your temporary credentials or use long-term credentials");else throw new nr(`Failed to validate credentials: ${i.message}`,"Verify your AWS credentials are correct and have the necessary permissions");throw i}return{valid:!0,accountId:r,region:n.region}}catch(n){if(n instanceof nr)throw n;return{valid:!1,error:n instanceof Error?n.message:"Unknown error"}}}async function Tg(e,n){return{allowed:n,denied:[]}}function Ku(e){let n=new Set(["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate","cloudformation:ListStacks"]);if(e.infrastructure){if(e.infrastructure.storage)n.add("s3:CreateBucket"),n.add("s3:DeleteBucket"),n.add("s3:PutBucketPolicy"),n.add("s3:PutBucketVersioning"),n.add("s3:PutBucketEncryption"),n.add("s3:PutObject"),n.add("s3:GetObject");if(e.infrastructure.compute){if(e.infrastructure.compute.server)n.add("ec2:RunInstances"),n.add("ec2:TerminateInstances"),n.add("ec2:DescribeInstances"),n.add("autoscaling:CreateAutoScalingGroup"),n.add("autoscaling:UpdateAutoScalingGroup"),n.add("autoscaling:DeleteAutoScalingGroup"),n.add("elasticloadbalancing:CreateLoadBalancer"),n.add("elasticloadbalancing:DeleteLoadBalancer");if(e.infrastructure.compute.fargate)n.add("ecs:CreateCluster"),n.add("ecs:DeleteCluster"),n.add("ecs:CreateService"),n.add("ecs:UpdateService"),n.add("ecs:DeleteService"),n.add("ecs:RegisterTaskDefinition")}if(e.infrastructure.database){if(e.infrastructure.database.postgres||e.infrastructure.database.mysql)n.add("rds:CreateDBInstance"),n.add("rds:DeleteDBInstance"),n.add("rds:ModifyDBInstance"),n.add("rds:DescribeDBInstances");if(e.infrastructure.database.dynamodb)n.add("dynamodb:CreateTable"),n.add("dynamodb:DeleteTable"),n.add("dynamodb:UpdateTable"),n.add("dynamodb:DescribeTable")}if(e.infrastructure.functions)n.add("lambda:CreateFunction"),n.add("lambda:DeleteFunction"),n.add("lambda:UpdateFunctionCode"),n.add("lambda:UpdateFunctionConfiguration"),n.add("lambda:AddPermission");if(e.infrastructure.cdn)n.add("cloudfront:CreateDistribution"),n.add("cloudfront:UpdateDistribution"),n.add("cloudfront:DeleteDistribution"),n.add("cloudfront:GetDistribution");if(e.infrastructure.network)n.add("ec2:CreateVpc"),n.add("ec2:DeleteVpc"),n.add("ec2:CreateSubnet"),n.add("ec2:DeleteSubnet"),n.add("ec2:CreateInternetGateway"),n.add("ec2:DeleteInternetGateway"),n.add("ec2:CreateNatGateway"),n.add("ec2:DeleteNatGateway"),n.add("ec2:CreateRouteTable"),n.add("ec2:DeleteRouteTable"),n.add("ec2:CreateSecurityGroup"),n.add("ec2:DeleteSecurityGroup")}return n.add("iam:CreateRole"),n.add("iam:DeleteRole"),n.add("iam:AttachRolePolicy"),n.add("iam:DetachRolePolicy"),n.add("iam:PutRolePolicy"),n.add("iam:GetRole"),n.add("iam:PassRole"),Array.from(n).sort()}function Eg(e){let n=Ku(e);return JSON.stringify({Version:"2012-10-17",Statement:[{Effect:"Allow",Action:n,Resource:"*"}]},null,2)}var xe={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 wg(e){let n=[];if(ve.verbose("Checking AWS service quotas..."),e.infrastructure?.compute?.server){let i=e.infrastructure.compute.server.autoScaling?.max||1;n.push({service:"EC2",quotaName:"Running On-Demand Instances",currentValue:i,limit:xe.ec2["Running On-Demand Instances"],percentage:i/xe.ec2["Running On-Demand Instances"]*100,warning:i>xe.ec2["Running On-Demand Instances"]*0.8})}if(e.infrastructure?.network?.vpc)n.push({service:"EC2",quotaName:"VPCs",currentValue:1,limit:xe.ec2.VPCs,percentage:1/xe.ec2.VPCs*100,warning:!1});if(e.infrastructure?.database?.postgres||e.infrastructure?.database?.mysql)n.push({service:"RDS",quotaName:"DB Instances",currentValue:1,limit:xe.rds["DB Instances"],percentage:1/xe.rds["DB Instances"]*100,warning:!1});if(e.infrastructure?.storage){let i=Object.keys(e.infrastructure.storage).length;n.push({service:"S3",quotaName:"Buckets",currentValue:i,limit:xe.s3.Buckets,percentage:i/xe.s3.Buckets*100,warning:i>xe.s3.Buckets*0.8})}if(e.infrastructure?.functions){let i=0;for(let s of Object.values(e.infrastructure.functions))if(Array.isArray(s))i+=s.length;n.push({service:"Lambda",quotaName:"Functions (estimated)",currentValue:i,limit:1000,percentage:i/1000*100,warning:i>800})}if(e.infrastructure?.database?.dynamodb){let i=e.infrastructure.database.dynamodb.tables?.length||0;n.push({service:"DynamoDB",quotaName:"Tables",currentValue:i,limit:xe.dynamodb.Tables,percentage:i/xe.dynamodb.Tables*100,warning:i>xe.dynamodb.Tables*0.8})}let r=n.filter((i)=>i.warning);if(r.length>0){ve.warn("Service quota warnings detected:");for(let i of r)ve.warn(` ${i.service} - ${i.quotaName}: ${i.currentValue}/${i.limit} (${i.percentage.toFixed(1)}%)`)}else ve.verbose("All service quotas are within limits");return n}function Ag(e){if(e.length===0)return"No quotas to check";let n=`Service Quota Usage:
|
|
2481
2479
|
|
|
2482
2480
|
`,r=e.reduce((i,s)=>{if(!i[s.service])i[s.service]=[];return i[s.service].push(s),i},{});for(let[i,s]of Object.entries(r)){n+=`${i}:
|
|
2483
2481
|
`;for(let a of s){let c=a.warning?"⚠":"✓";n+=` ${c} ${a.quotaName}: ${a.currentValue}/${a.limit} (${a.percentage.toFixed(1)}%)
|
|
2484
2482
|
`}n+=`
|
|
2485
|
-
`}return n}function
|
|
2486
|
-
`);return
|
|
2487
|
-
`)}function Ig(e,n,r){if(e.deleted.length>0)return!0;for(let i of e.modified){let s=n.Resources[i],a=r.Resources[i];if(s.Type!==a.Type)return!0;let c=Bi(a.Type);for(let u of c){let d=s.Properties?.[u],m=a.Properties?.[u];if(JSON.stringify(d)!==JSON.stringify(m))return!0}}return!1}function Bi(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 Pg(e){let n=[],r=[],i=[];n.push(...e.added);for(let s of e.modified)r.push(s);return i.push(...e.deleted),{safe:n,caution:r,dangerous:i}}function Dg(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 kg(e){let n=e.added.length+e.modified.length+e.deleted.length+e.unchanged.length,r=e.added.length+e.modified.length+e.deleted.length,i=n>0?r/n*100:0;return{total:n,added:e.added.length,modified:e.modified.length,deleted:e.deleted.length,unchanged:e.unchanged.length,changePercentage:i}}var ju={$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 Ng(e){let n=[];if(!e.project)n.push("Missing required field: project");else{if(!e.project.name)n.push("Missing required field: project.name");if(!e.project.slug)n.push("Missing required field: project.slug")}if(e.project?.slug&&!/^[a-z0-9-]+$/.test(e.project.slug))n.push("Invalid project.slug: must contain only lowercase letters, numbers, and hyphens");let r=["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","sa-east-1","ca-central-1"];if(e.project?.region&&!r.includes(e.project.region))n.push(`Invalid region: ${e.project.region}. Must be one of: ${r.join(", ")}`);if(e.mode&&!["server","serverless"].includes(e.mode))n.push("Invalid mode: must be one of server or serverless");return{valid:n.length===0,errors:n}}var wl={enabled:process.env.TS_CLOUD_LOCAL==="true"||!1,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 Oa(){return wl}function xg(){return wl.enabled}function _g(e){let n=Oa();if(!n.enabled)return"";switch(e.toLowerCase()){case"dynamodb":return n.dynamodbEndpoint;case"s3":return n.s3Endpoint;case"localstack":case"cloudformation":case"lambda":case"apigateway":case"sns":case"sqs":case"cloudwatch":case"iam":case"sts":return n.localstackEndpoint;default:return n.localstackEndpoint}}function Og(){let e=Oa();return{accessKeyId:e.awsAccessKeyId,secretAccessKey:e.awsSecretAccessKey,region:e.awsRegion}}function $g(){let e=Oa();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 Al{stacks=new Map;stackEvents=new Map;async createStack(e){let n=`arn:aws:cloudformation:${e.region||"us-east-1"}:123456789012:stack/${e.StackName}/${Date.now()}`;return this.stacks.set(e.StackName,{StackId:n,StackName:e.StackName,StackStatus:"CREATE_IN_PROGRESS",CreationTime:new Date().toISOString(),TemplateBody:e.TemplateBody,Parameters:e.Parameters||[]}),this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_IN_PROGRESS"}),setTimeout(()=>{let r=this.stacks.get(e.StackName);if(r)r.StackStatus="CREATE_COMPLETE",this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_COMPLETE"})},100),{StackId:n}}async updateStack(e){let n=this.stacks.get(e.StackName);if(!n)throw Error(`Stack ${e.StackName} does not exist`);return n.StackStatus="UPDATE_IN_PROGRESS",n.TemplateBody=e.TemplateBody||n.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(()=>{n.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:n.StackId}}async deleteStack(e){let n=this.stacks.get(e.StackName);if(!n)throw Error(`Stack ${e.StackName} does not exist`);n.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 n=this.stacks.get(e.StackName);if(!n)throw Error(`Stack ${e.StackName} does not exist`);return{Stacks:[n]}}return{Stacks:Array.from(this.stacks.values())}}async describeStackEvents(e){return{StackEvents:this.stackEvents.get(e.StackName)||[]}}addEvent(e,n){if(!this.stackEvents.has(e))this.stackEvents.set(e,[]);this.stackEvents.get(e).unshift(n)}reset(){this.stacks.clear(),this.stackEvents.clear()}}class Rl{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 n=this.buckets.get(e.Bucket);if(!n)n=new Map,this.buckets.set(e.Bucket,n);return n.set(e.Key,Buffer.from(e.Body||"")),{ETag:`"${Date.now()}"`}}async getObject(e){let n=this.buckets.get(e.Bucket);if(!n)throw Error(`Bucket ${e.Bucket} does not exist`);let r=n.get(e.Key);if(!r)throw Error(`Object ${e.Key} does not exist`);return{Body:r,ContentLength:r.length}}async deleteObject(e){let n=this.buckets.get(e.Bucket);if(n)n.delete(e.Key)}async listObjects(e){let n=this.buckets.get(e.Bucket);if(!n)throw Error(`Bucket ${e.Bucket} does not exist`);return{Contents:Array.from(n.keys()).map((i)=>({Key:i,Size:n.get(i).length,LastModified:new Date().toISOString()}))}}reset(){this.buckets.clear()}}class Il{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 n=this.data.get(e.TableName);if(!n)n=new Map,this.data.set(e.TableName,n);let r=JSON.stringify(e.Item);n.set(r,e.Item)}async getItem(e){let n=this.data.get(e.TableName);if(!n)return{};let r=JSON.stringify(e.Key),i=n.get(r);return i?{Item:i}:{}}async deleteItem(e){let n=this.data.get(e.TableName);if(n){let r=JSON.stringify(e.Key);n.delete(r)}}async scan(e){let n=this.data.get(e.TableName);if(!n)return{Items:[]};return{Items:Array.from(n.values())}}reset(){this.tables.clear(),this.data.clear()}}function Lg(e){return{cloudformation:new Al,s3:new Rl,dynamodb:new Il}}class $a{environments=new Map;async createPreviewEnvironment(e){let{branch:n,pr:r,commitSha:i,ttl:s=24,baseConfig:a,region:c="us-east-1"}=e,u=this.generatePreviewId(n,r,i),d=this.generatePreviewName(n,r),m=`preview-${d}`,p=new Date,g=new Date(p.getTime()+s*60*60*1000),y={id:u,name:d,branch:n,pr:r,commitSha:i,createdAt:p,expiresAt:g,status:"creating",stackName:m,region:c,resources:[]};this.environments.set(u,y);try{let f=this.createPreviewConfig(a,d);return y.status="active",y.url=`https://${d}.preview.example.com`,y}catch(f){throw y.status="failed",f}}async destroyPreviewEnvironment(e){let n=this.environments.get(e);if(!n)throw Error(`Preview environment ${e} not found`);n.status="destroying";try{n.status="destroyed",this.environments.delete(e)}catch(r){throw Error(`Failed to destroy preview environment: ${r}`)}}getPreviewEnvironment(e){return this.environments.get(e)}getPreviewEnvironmentByBranch(e){return Array.from(this.environments.values()).find((n)=>n.branch===e)}getPreviewEnvironmentByPR(e){return Array.from(this.environments.values()).find((n)=>n.pr===e)}listPreviewEnvironments(){return Array.from(this.environments.values())}listActivePreviewEnvironments(){return this.listPreviewEnvironments().filter((e)=>e.status==="active")}async cleanupExpiredEnvironments(e={}){let{maxAge:n,keepCount:r,dryRun:i=!1}=e,s=[],a=[],c=new Date,u=this.listPreviewEnvironments().sort((d,m)=>m.createdAt.getTime()-d.createdAt.getTime());for(let d=0;d<u.length;d++){let m=u[d];if(m.status!=="active")continue;let p=!1;if(m.expiresAt<c)p=!0;if(n){if((c.getTime()-m.createdAt.getTime())/3600000>n)p=!0}if(r&&d>=r)p=!0;if(p)if(i)s.push(m.id);else try{await this.destroyPreviewEnvironment(m.id),s.push(m.id)}catch(g){a.push(m.id)}}return{destroyed:s,failed:a}}async updatePreviewEnvironment(e,n){let r=this.environments.get(e);if(!r)throw Error(`Preview environment ${e} not found`);r.commitSha=n,r.status="creating";try{return r.status="active",r}catch(i){throw r.status="failed",i}}async getPreviewEnvironmentsCost(){let e={},n=0;for(let r of this.environments.values())e[r.id]=0,n+=0;return{total:n,byEnvironment:e}}generatePreviewId(e,n,r){let i=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase(),s=r?.substring(0,7)||Date.now().toString();return n?`pr-${n}-${s}`:`${i}-${s}`}generatePreviewName(e,n){let r=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase();return n?`pr-${n}`:r}createPreviewConfig(e,n){return{...e,project:{...e.project,name:`${e.project.name} Preview (${n})`,slug:`${e.project.slug}-preview-${n}`}}}}var Vu=new $a;function zu(e={}){let{workflowName:n="Preview Environment",trigger:r="pull_request",branches:i=["main","develop"],awsRegion:s="us-east-1",awsRole:a,configFile:c="cloud.config.ts",ttl:u=24}=e;return`name: ${n}
|
|
2483
|
+
`}return n}function Rg(e){let n=[];for(let r of e)if(r.percentage>=100)n.push(`Request quota increase for ${r.service} - ${r.quotaName} (currently ${r.limit})`);else if(r.warning)n.push(`Consider requesting quota increase for ${r.service} - ${r.quotaName} (${r.percentage.toFixed(1)}% used)`);return n}import{createHash as sr}from"node:crypto";import{existsSync as st,mkdirSync as Ms,readdirSync as Zn,readFileSync as Xn,unlinkSync as Je,writeFileSync as Ls}from"node:fs";import{join as Mt}from"node:path";class Ba{cacheDir;ttl;constructor(e,n={}){this.cacheDir=e,this.ttl=n.ttl||86400000}ensureCacheDir(){if(!st(this.cacheDir))Ms(this.cacheDir,{recursive:!0})}getCachePath(e){let n=sr("sha256").update(e).digest("hex");return Mt(this.cacheDir,`${n}.json`)}get(e){let n=this.getCachePath(e);if(!st(n))return;try{let r=Xn(n,"utf-8"),i=JSON.parse(r);if(Date.now()-i.timestamp>this.ttl){Je(n);return}return i.value}catch{Je(n);return}}set(e,n,r){this.ensureCacheDir();let i=this.getCachePath(e),s={value:n,timestamp:Date.now(),hash:r};Ls(i,JSON.stringify(s),"utf-8")}has(e){return this.get(e)!==void 0}clear(){if(!st(this.cacheDir))return;let e=Zn(this.cacheDir);for(let n of e)Je(Mt(this.cacheDir,n))}prune(){if(!st(this.cacheDir))return;let e=Zn(this.cacheDir),n=Date.now();for(let r of e){let i=Mt(this.cacheDir,r);try{let s=Xn(i,"utf-8"),a=JSON.parse(s);if(n-a.timestamp>this.ttl)Je(i)}catch{Je(i)}}}}class Fa{cache;constructor(e=He("cache","templates")){this.cache=new Ba(e,{ttl:86400000})}getTemplate(e){return this.cache.get(`template:${e}`)}setTemplate(e,n){let r=this.hashTemplate(n);this.cache.set(`template:${e}`,n,r)}hasChanged(e,n){let r=this.cache.get(`template:${e}`);if(!r)return!0;let i=this.hashTemplate(r),s=this.hashTemplate(n);return i!==s}hashTemplate(e){return sr("sha256").update(e).digest("hex")}clear(){this.cache.clear()}prune(){this.cache.prune()}}var Bt=null;function Ju(){if(!Bt)Bt=new Fa;return Bt}import{createHash as Ft}from"node:crypto";import{createReadStream as Os,readdirSync as $s,statSync as at}from"node:fs";import{join as Bs,relative as Fs}from"node:path";async function xl(e,n={}){let r=n.algorithm||"sha256",i=n.chunkSize||65536;return new Promise((s,a)=>{let c=Ft(r),u=Os(e,{highWaterMark:i});u.on("data",(d)=>c.update(d)),u.on("end",()=>s(c.digest("hex"))),u.on("error",a)})}function _l(e,n="sha256"){return Ft(n).update(e).digest("hex")}function Ig(e,n="sha256"){return Ft(n).update(e).digest("hex")}async function Pg(e,n={}){let r=n.ignorePatterns||["node_modules",".git","dist","build",An()],i=[];async function s(a){let c=$s(a,{withFileTypes:!0});for(let u of c){let d=Bs(a,u.name),m=Fs(e,d);if(r.some((p)=>m.includes(p)))continue;if(u.isDirectory())await s(d);else if(u.isFile()){let p=at(d),g=await xl(d,n);i.push({path:m,hash:g,size:p.size,mtime:p.mtimeMs})}}}return await s(e),i}function Dg(e){let r=[...e].sort((i,s)=>i.path.localeCompare(s.path)).map((i)=>`${i.path}:${i.hash}`).join(`
|
|
2484
|
+
`);return _l(r)}function kg(e){let n=at(e);return _l(`${e}:${n.size}:${n.mtimeMs}`)}function Ng(e,n){let r=new Map(e.map((u)=>[u.path,u])),i=new Map(n.map((u)=>[u.path,u])),s=[],a=[],c=[];for(let[u,d]of i){let m=r.get(u);if(!m)s.push(d);else if(m.hash!==d.hash)a.push(d)}for(let[u,d]of r)if(!i.has(u))c.push(d);return{added:s,modified:a,deleted:c}}class Xu{cache;constructor(){this.cache=new Map}get(e){let n=at(e),r=this.cache.get(e);if(r&&r.mtime===n.mtimeMs&&r.size===n.size)return r.hash;return}set(e,n){let r=at(e);this.cache.set(e,{hash:n,mtime:r.mtimeMs,size:r.size})}async getOrCompute(e,n={}){let r=this.get(e);if(r)return r;let i=await xl(e,n);return this.set(e,i),i}clear(){this.cache.clear()}}async function ja(e,n={}){let r=n.concurrency||5,i=n.stopOnError??!0,s=[],a=[],c=Date.now(),u=[...e],d=[];async function m(y,f){try{let h=await y();s[f]=h}catch(h){let S=h instanceof Error?h:Error(String(h));if(a.push(S),i)throw u.length=0,S}}let p=0;while(u.length>0||d.length>0){while(d.length<r&&u.length>0){let y=u.shift(),f=p++,h=m(y,f);d.push(h)}if(d.length>0){await Promise.race(d);for(let y=d.length-1;y>=0;y--)if(await Promise.race([d[y].then(()=>!0),Promise.resolve(!1)]))d.splice(y,1)}if(i&&a.length>0)break}let g=Date.now()-c;return{results:s.filter((y)=>y!==void 0),errors:a,duration:g}}async function xg(e,n,r={}){let i=e.map((s)=>()=>n(s));return ja(i,r)}async function _g(e,n,r=5){let i=e.map((a,c)=>()=>n(a,c)),s=await ja(i,{concurrency:r,stopOnError:!1});if(s.errors.length>0)throw AggregateError(s.errors,"Parallel map failed");return s.results}async function Og(e,n={}){let r=n.retries||3,i=n.retryDelay||1000,s=e.map((a)=>async()=>{let c;for(let u=0;u<=r;u++)try{return await a()}catch(d){if(c=d instanceof Error?d:Error(String(d)),u<r)await ar(i*(u+1))}throw c});return ja(s,n)}async function $g(e){let n=[];for(let r of e){let i=await r();n.push(i)}return n}function ar(e){return new Promise((n)=>setTimeout(n,e))}async function Lg(e,n,r="Operation timed out"){return Promise.race([e(),new Promise((i,s)=>setTimeout(()=>s(Error(r)),n))])}class Qu{maxConcurrent;minInterval;queue=[];running=0;lastExecution=0;constructor(e=5,n=100){this.maxConcurrent=e;this.minInterval=n}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 ar(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 Yu(e,n){let r=[];for(let i=0;i<e.length;i+=n)r.push(e.slice(i,i+n));return r}async function Mg(e,n,r){let i=Yu(e,n),s=[];for(let a of i){let c=await r(a);s.push(...c)}return s}function Ug(e,n){let r=[],i=[],s=[],a=[],c=e.Resources||{},u=n.Resources||{},d=new Set(Object.keys(c)),m=new Set(Object.keys(u));for(let y of m)if(!d.has(y))r.push(y);for(let y of d)if(!m.has(y))s.push(y);for(let y of m)if(d.has(y)){let f=c[y],h=u[y];if(JSON.stringify(f)!==JSON.stringify(h))i.push(y);else a.push(y)}let p=JSON.stringify(e.Parameters||{})!==JSON.stringify(n.Parameters||{}),g=JSON.stringify(e.Outputs||{})!==JSON.stringify(n.Outputs||{});return{added:r,modified:i,deleted:s,unchanged:a,parametersChanged:p,outputsChanged:g,hasChanges:r.length>0||i.length>0||s.length>0||p||g}}function Bg(e){let n=[];if(!e.hasChanges)return"No changes detected";if(e.added.length>0){n.push(`Added resources (${e.added.length}):`);for(let r of e.added)n.push(` + ${r}`)}if(e.modified.length>0){n.push(`Modified resources (${e.modified.length}):`);for(let r of e.modified)n.push(` ~ ${r}`)}if(e.deleted.length>0){n.push(`Deleted resources (${e.deleted.length}):`);for(let r of e.deleted)n.push(` - ${r}`)}if(e.parametersChanged)n.push("Parameters changed");if(e.outputsChanged)n.push("Outputs changed");return n.join(`
|
|
2485
|
+
`)}function Fg(e,n,r){if(e.deleted.length>0)return!0;for(let i of e.modified){let s=n.Resources[i],a=r.Resources[i];if(s.Type!==a.Type)return!0;let c=Gs(a.Type);for(let u of c){let d=s.Properties?.[u],m=a.Properties?.[u];if(JSON.stringify(d)!==JSON.stringify(m))return!0}}return!1}function Gs(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 jg(e){let n=[],r=[],i=[];n.push(...e.added);for(let s of e.modified)r.push(s);return i.push(...e.deleted),{safe:n,caution:r,dangerous:i}}function Vg(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 zg(e){let n=e.added.length+e.modified.length+e.deleted.length+e.unchanged.length,r=e.added.length+e.modified.length+e.deleted.length,i=n>0?r/n*100:0;return{total:n,added:e.added.length,modified:e.modified.length,deleted:e.deleted.length,unchanged:e.unchanged.length,changePercentage:i}}var Zu={$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 Hg(e){let n=[];if(!e.project)n.push("Missing required field: project");else{if(!e.project.name)n.push("Missing required field: project.name");if(!e.project.slug)n.push("Missing required field: project.slug")}if(e.project?.slug&&!/^[a-z0-9-]+$/.test(e.project.slug))n.push("Invalid project.slug: must contain only lowercase letters, numbers, and hyphens");let r=["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","sa-east-1","ca-central-1"];if(e.project?.region&&!r.includes(e.project.region))n.push(`Invalid region: ${e.project.region}. Must be one of: ${r.join(", ")}`);if(e.mode&&!["server","serverless"].includes(e.mode))n.push("Invalid mode: must be one of server or serverless");return{valid:n.length===0,errors:n}}var Ol={enabled:process.env.TS_CLOUD_LOCAL==="true"||!1,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 Va(){return Ol}function Gg(){return Ol.enabled}function qg(e){let n=Va();if(!n.enabled)return"";switch(e.toLowerCase()){case"dynamodb":return n.dynamodbEndpoint;case"s3":return n.s3Endpoint;case"localstack":case"cloudformation":case"lambda":case"apigateway":case"sns":case"sqs":case"cloudwatch":case"iam":case"sts":return n.localstackEndpoint;default:return n.localstackEndpoint}}function Wg(){let e=Va();return{accessKeyId:e.awsAccessKeyId,secretAccessKey:e.awsSecretAccessKey,region:e.awsRegion}}function Kg(){let e=Va();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 $l{stacks=new Map;stackEvents=new Map;async createStack(e){let n=`arn:aws:cloudformation:${e.region||"us-east-1"}:123456789012:stack/${e.StackName}/${Date.now()}`;return this.stacks.set(e.StackName,{StackId:n,StackName:e.StackName,StackStatus:"CREATE_IN_PROGRESS",CreationTime:new Date().toISOString(),TemplateBody:e.TemplateBody,Parameters:e.Parameters||[]}),this.addEvent(e.StackName,{EventId:Date.now().toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_IN_PROGRESS"}),setTimeout(()=>{let r=this.stacks.get(e.StackName);if(r)r.StackStatus="CREATE_COMPLETE",this.addEvent(e.StackName,{EventId:(Date.now()+1).toString(),StackName:e.StackName,LogicalResourceId:e.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_COMPLETE"})},100),{StackId:n}}async updateStack(e){let n=this.stacks.get(e.StackName);if(!n)throw Error(`Stack ${e.StackName} does not exist`);return n.StackStatus="UPDATE_IN_PROGRESS",n.TemplateBody=e.TemplateBody||n.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(()=>{n.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:n.StackId}}async deleteStack(e){let n=this.stacks.get(e.StackName);if(!n)throw Error(`Stack ${e.StackName} does not exist`);n.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 n=this.stacks.get(e.StackName);if(!n)throw Error(`Stack ${e.StackName} does not exist`);return{Stacks:[n]}}return{Stacks:Array.from(this.stacks.values())}}async describeStackEvents(e){return{StackEvents:this.stackEvents.get(e.StackName)||[]}}addEvent(e,n){if(!this.stackEvents.has(e))this.stackEvents.set(e,[]);this.stackEvents.get(e).unshift(n)}reset(){this.stacks.clear(),this.stackEvents.clear()}}class Ll{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 n=this.buckets.get(e.Bucket);if(!n)n=new Map,this.buckets.set(e.Bucket,n);return n.set(e.Key,Buffer.from(e.Body||"")),{ETag:`"${Date.now()}"`}}async getObject(e){let n=this.buckets.get(e.Bucket);if(!n)throw Error(`Bucket ${e.Bucket} does not exist`);let r=n.get(e.Key);if(!r)throw Error(`Object ${e.Key} does not exist`);return{Body:r,ContentLength:r.length}}async deleteObject(e){let n=this.buckets.get(e.Bucket);if(n)n.delete(e.Key)}async listObjects(e){let n=this.buckets.get(e.Bucket);if(!n)throw Error(`Bucket ${e.Bucket} does not exist`);return{Contents:Array.from(n.keys()).map((i)=>({Key:i,Size:n.get(i).length,LastModified:new Date().toISOString()}))}}reset(){this.buckets.clear()}}class Ml{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 n=this.data.get(e.TableName);if(!n)n=new Map,this.data.set(e.TableName,n);let r=JSON.stringify(e.Item);n.set(r,e.Item)}async getItem(e){let n=this.data.get(e.TableName);if(!n)return{};let r=JSON.stringify(e.Key),i=n.get(r);return i?{Item:i}:{}}async deleteItem(e){let n=this.data.get(e.TableName);if(n){let r=JSON.stringify(e.Key);n.delete(r)}}async scan(e){let n=this.data.get(e.TableName);if(!n)return{Items:[]};return{Items:Array.from(n.values())}}reset(){this.tables.clear(),this.data.clear()}}function Jg(e){return{cloudformation:new $l,s3:new Ll,dynamodb:new Ml}}class za{environments=new Map;async createPreviewEnvironment(e){let{branch:n,pr:r,commitSha:i,ttl:s=24,baseConfig:a,region:c="us-east-1"}=e,u=this.generatePreviewId(n,r,i),d=this.generatePreviewName(n,r),m=`preview-${d}`,p=new Date,g=new Date(p.getTime()+s*60*60*1000),y={id:u,name:d,branch:n,pr:r,commitSha:i,createdAt:p,expiresAt:g,status:"creating",stackName:m,region:c,resources:[]};this.environments.set(u,y);try{let f=this.createPreviewConfig(a,d);return y.status="active",y.url=`https://${d}.preview.example.com`,y}catch(f){throw y.status="failed",f}}async destroyPreviewEnvironment(e){let n=this.environments.get(e);if(!n)throw Error(`Preview environment ${e} not found`);n.status="destroying";try{n.status="destroyed",this.environments.delete(e)}catch(r){throw Error(`Failed to destroy preview environment: ${r}`)}}getPreviewEnvironment(e){return this.environments.get(e)}getPreviewEnvironmentByBranch(e){return Array.from(this.environments.values()).find((n)=>n.branch===e)}getPreviewEnvironmentByPR(e){return Array.from(this.environments.values()).find((n)=>n.pr===e)}listPreviewEnvironments(){return Array.from(this.environments.values())}listActivePreviewEnvironments(){return this.listPreviewEnvironments().filter((e)=>e.status==="active")}async cleanupExpiredEnvironments(e={}){let{maxAge:n,keepCount:r,dryRun:i=!1}=e,s=[],a=[],c=new Date,u=this.listPreviewEnvironments().sort((d,m)=>m.createdAt.getTime()-d.createdAt.getTime());for(let d=0;d<u.length;d++){let m=u[d];if(m.status!=="active")continue;let p=!1;if(m.expiresAt<c)p=!0;if(n){if((c.getTime()-m.createdAt.getTime())/3600000>n)p=!0}if(r&&d>=r)p=!0;if(p)if(i)s.push(m.id);else try{await this.destroyPreviewEnvironment(m.id),s.push(m.id)}catch(g){a.push(m.id)}}return{destroyed:s,failed:a}}async updatePreviewEnvironment(e,n){let r=this.environments.get(e);if(!r)throw Error(`Preview environment ${e} not found`);r.commitSha=n,r.status="creating";try{return r.status="active",r}catch(i){throw r.status="failed",i}}async getPreviewEnvironmentsCost(){let e={},n=0;for(let r of this.environments.values())e[r.id]=0,n+=0;return{total:n,byEnvironment:e}}generatePreviewId(e,n,r){let i=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase(),s=r?.substring(0,7)||Date.now().toString();return n?`pr-${n}-${s}`:`${i}-${s}`}generatePreviewName(e,n){let r=e.replace(/[^a-z0-9-]/gi,"-").toLowerCase();return n?`pr-${n}`:r}createPreviewConfig(e,n){return{...e,project:{...e.project,name:`${e.project.name} Preview (${n})`,slug:`${e.project.slug}-preview-${n}`}}}}var ep=new za;function tp(e={}){let{workflowName:n="Preview Environment",trigger:r="pull_request",branches:i=["main","develop"],awsRegion:s="us-east-1",awsRole:a,configFile:c="cloud.config.ts",ttl:u=24}=e;return`name: ${n}
|
|
2488
2486
|
|
|
2489
2487
|
on:
|
|
2490
2488
|
${r}:
|
|
@@ -2618,7 +2616,7 @@ jobs:
|
|
|
2618
2616
|
run: |
|
|
2619
2617
|
# Clean up environments older than TTL
|
|
2620
2618
|
bun run cloud env:cleanup --max-age=\${{ env.TTL_HOURS }}
|
|
2621
|
-
`}function
|
|
2619
|
+
`}function rp(e={}){let{schedule:n="0 0 * * *",maxAge:r=48,keepCount:i=10}=e;return`name: Cleanup Stale Preview Environments
|
|
2622
2620
|
|
|
2623
2621
|
on:
|
|
2624
2622
|
schedule:
|
|
@@ -2663,7 +2661,7 @@ jobs:
|
|
|
2663
2661
|
- name: Report cleanup results
|
|
2664
2662
|
run: |
|
|
2665
2663
|
bun run cloud env:list --status=destroyed
|
|
2666
|
-
`}function
|
|
2664
|
+
`}function np(e={}){let{schedule:n="0 8 * * 1",webhookUrl:r}=e;return`name: Preview Environment Cost Report
|
|
2667
2665
|
|
|
2668
2666
|
on:
|
|
2669
2667
|
schedule:
|
|
@@ -2712,15 +2710,15 @@ jobs:
|
|
|
2712
2710
|
curl -X POST -H 'Content-type: application/json' \\
|
|
2713
2711
|
--data '{"text":"Preview Environment Cost Report\\n\${{ steps.cost.outputs.cost_json }}"}' \\
|
|
2714
2712
|
$SLACK_WEBHOOK_URL`:'run: |\n echo "${{ steps.cost.outputs.cost_json }}"'}
|
|
2715
|
-
`}class
|
|
2716
|
-
`)}function
|
|
2717
|
-
`)}function
|
|
2718
|
-
`)}function
|
|
2719
|
-
`)}class
|
|
2713
|
+
`}class Ha{channels=[];addChannel(e){this.channels.push(e)}removeChannel(e){this.channels=this.channels.filter((n)=>n.type!==e)}async notify(e){let n=this.channels.map((r)=>this.sendToChannel(r,e));await Promise.allSettled(n)}async sendToChannel(e,n){switch(e.type){case"slack":await this.sendToSlack(e.config,n);break;case"discord":await this.sendToDiscord(e.config,n);break;case"email":await this.sendToEmail(e.config,n);break;case"webhook":await this.sendToWebhook(e.config,n);break}}async sendToSlack(e,n){let r=this.formatSlackMessage(n,e),i=await fetch(e.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!i.ok)throw Error(`Failed to send Slack notification: ${i.statusText}`)}formatSlackMessage(e,n){let{environment:r,type:i}=e,s={created:":rocket:",updated:":arrows_counterclockwise:",destroyed:":wastebasket:",failed:":x:",expired:":hourglass_flowing_sand:"}[i],a={created:"#36a64f",updated:"#2196F3",destroyed:"#808080",failed:"#f44336",expired:"#ff9800"}[i],c={created:"Preview Environment Created",updated:"Preview Environment Updated",destroyed:"Preview Environment Destroyed",failed:"Preview Environment Failed",expired:"Preview Environment Expired"}[i];return{username:n.username||"ts-cloud",icon_emoji:n.iconEmoji||":cloud:",channel:n.channel,attachments:[{color:a,title:`${s} ${c}`,fields:[{title:"Environment",value:r.name,short:!0},{title:"Branch",value:r.branch,short:!0},...r.pr?[{title:"PR",value:`#${r.pr}`,short:!0}]:[],{title:"Commit",value:r.commitSha.substring(0,7),short:!0},...r.url?[{title:"URL",value:r.url,short:!1}]:[],...i==="created"?[{title:"Expires",value:r.expiresAt.toLocaleString(),short:!0}]:[]],footer:"ts-cloud Preview Environments",ts:Math.floor(e.timestamp.getTime()/1000)}]}}async sendToDiscord(e,n){let r=this.formatDiscordMessage(n,e),i=await fetch(e.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!i.ok)throw Error(`Failed to send Discord notification: ${i.statusText}`)}formatDiscordMessage(e,n){let{environment:r,type:i}=e,s={created:":rocket:",updated:":arrows_counterclockwise:",destroyed:":wastebasket:",failed:":x:",expired:":hourglass:"}[i],a={created:3581519,updated:2201331,destroyed:8421504,failed:16007990,expired:16750592}[i],c={created:"Preview Environment Created",updated:"Preview Environment Updated",destroyed:"Preview Environment Destroyed",failed:"Preview Environment Failed",expired:"Preview Environment Expired"}[i];return{username:n.username||"ts-cloud",avatar_url:n.avatarUrl,embeds:[{title:`${s} ${c}`,color:a,fields:[{name:"Environment",value:r.name,inline:!0},{name:"Branch",value:r.branch,inline:!0},...r.pr?[{name:"PR",value:`#${r.pr}`,inline:!0}]:[],{name:"Commit",value:`\`${r.commitSha.substring(0,7)}\``,inline:!0},...r.url?[{name:"URL",value:r.url,inline:!1}]:[]],timestamp:e.timestamp.toISOString(),footer:{text:"ts-cloud Preview Environments"}}]}}async sendToEmail(e,n){console.log(`Email notification would be sent to ${e.to.join(", ")}`)}async sendToWebhook(e,n){let r=await fetch(e.url,{method:e.method||"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify({event:n.type,environment:n.environment,timestamp:n.timestamp.toISOString(),metadata:n.metadata})});if(!r.ok)throw Error(`Failed to send webhook notification: ${r.statusText}`)}}var ip=new Ha;function Xg(e){let{columns:n,data:r,border:i=!0,header:s=!0,compact:a=!1,maxWidth:c}=e;if(r.length===0)return"No data to display";let u=n.map((m)=>{let p=m.label.length,g=Math.max(...r.map((f)=>(m.formatter?m.formatter(f[m.key]):String(f[m.key]||"")).length)),y=m.width||Math.max(p,g);if(c&&y>c)y=c;return y}),d=[];if(i)d.push(Gt(u,"top",a));if(s){if(d.push(or(n.map((m)=>m.label),u,n.map((m)=>m.align||"left"),i)),i)d.push(Gt(u,"middle",a))}for(let m of r){let p=n.map((g)=>{let y=g.formatter?g.formatter(m[g.key]):String(m[g.key]||"");return Vs(y,u[n.indexOf(g)])});d.push(or(p,u,n.map((g)=>g.align||"left"),i))}if(i)d.push(Gt(u,"bottom",a));return d.join(`
|
|
2714
|
+
`)}function or(e,n,r,i){let s=e.map((a,c)=>{let u=n[c],d=r[c];return Ws(a,u,d)});if(i)return`│ ${s.join(" │ ")} │`;return s.join(" ")}function Gt(e,n,r){let i=n==="top"?"┌":n==="middle"?"├":"└",s=n==="top"?"┐":n==="middle"?"┤":"┘",a=n==="top"?"┬":n==="middle"?"┼":"┴",c="─";if(r)return i+e.map((u)=>"─".repeat(u+2)).join(a)+s;return i+e.map((u)=>"─".repeat(u+2)).join(a)+s}function Ws(e,n,r){let i=cr(e).length;if(i>=n)return e;let s=n-i;switch(r){case"right":return" ".repeat(s)+e;case"center":{let a=Math.floor(s/2),c=s-a;return" ".repeat(a)+e+" ".repeat(c)}default:return e+" ".repeat(s)}}function Vs(e,n){if(cr(e).length<=n)return e;return e.substring(0,n-1)+"…"}function cr(e){return e.replace(/\x1B\[[0-9;]*m/g,"")}function Qg(e,n={}){let{indent:r=" ",showMetadata:i=!1}=n,s=[];function a(c,u,d){let p=u+(d?"└─ ":"├─ ")+c.label;if(s.push(p),i&&c.metadata){let g=u+(d?" ":"│ ");for(let[y,f]of Object.entries(c.metadata))s.push(`${g}${y}: ${f}`)}if(c.children&&c.children.length>0){let g=u+(d?" ":"│ ");c.children.forEach((y,f)=>{a(y,g,f===c.children.length-1)})}}return e.forEach((c,u)=>{a(c,"",u===e.length-1)}),s.join(`
|
|
2715
|
+
`)}function Yg(e){let{total:n,current:r,width:i=40,format:s=":bar :percent :current/:total",complete:a="█",incomplete:c="░"}=e,u=Math.min(100,Math.max(0,r/n*100)),d=Math.floor(i*r/n),m=i-d,p=a.repeat(d)+c.repeat(m);return s.replace(":bar",p).replace(":percent",`${u.toFixed(0)}%`).replace(":current",String(r)).replace(":total",String(n))}function Zg(e,n=2){if(e===0)return"0 Bytes";let r=1024,i=n<0?0:n,s=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],a=Math.floor(Math.log(e)/Math.log(r));return`${Number.parseFloat((e/Math.pow(r,a)).toFixed(i))} ${s[a]}`}function ef(e){if(e<1000)return`${e}ms`;let n=Math.floor(e/1000);if(n<60)return`${n}s`;let r=Math.floor(n/60),i=n%60;if(r<60)return i>0?`${r}m ${i}s`:`${r}m`;let s=Math.floor(r/60),a=r%60;if(s<24)return a>0?`${s}h ${a}m`:`${s}h`;let c=Math.floor(s/24),u=s%24;return u>0?`${c}d ${u}h`:`${c}d`}function tf(e,n="•"){return e.map((r)=>`${n} ${r}`).join(`
|
|
2716
|
+
`)}function rf(e,n={}){let{indent:r="",separator:i=": "}=n,s=Math.max(...Object.keys(e).map((a)=>a.length));return Object.entries(e).map(([a,c])=>{let u=a.padEnd(s);return`${r}${u}${i}${c}`}).join(`
|
|
2717
|
+
`)}class op{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,n=this.current/e,r=this.total-this.current;return Math.round(r/n)}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 n=Math.floor(e/60000);if(n<60)return`${n}m`;let r=Math.floor(n/60),i=n%60;if(r<24)return i>0?`${r}h ${i}m`:`${r}h`;let s=Math.floor(r/24),a=r%24;return a>0?`${s}d ${a}h`:`${s}d`}render(){let e=this.getPercentage(),n=Math.floor(this.width*this.current/this.total),r=this.width-n,i="█".repeat(n)+"░".repeat(r),s=`${e.toFixed(1)}%`,a=`${this.current}/${this.total}`,c=this.showETA?`ETA: ${this.getETAFormatted()}`:"",u=this.format.replace(":message",this.message).replace(":bar",i).replace(":percent",this.showPercentage?s:"").replace(":counter",this.showCounter?a:"").replace(":eta",c).replace(":current",String(this.current)).replace(":total",String(this.total));return u=u.replace(/\s+/g," ").trim(),u}isComplete(){return this.current>=this.total}}class sp{steps;currentStepIndex=0;constructor(e){this.steps=e.map((n)=>({name:n,status:"pending"}))}startStep(e,n){if(e>=0&&e<this.steps.length)this.steps[e].status="active",this.steps[e].message=n,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 n of this.steps){let i=`${this.getStatusIcon(n.status)} ${n.name}`;if(n.message)i+=` - ${n.message}`;if(n.error)i+=`
|
|
2720
2718
|
Error: ${n.error}`;e.push(i)}return e.join(`
|
|
2721
|
-
`)}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
|
|
2719
|
+
`)}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 ap{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 cp{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,n){if(e>=0&&e<this.tasks.length)this.tasks[e].status="completed",this.tasks[e].output=n}fail(e,n){if(e>=0&&e<this.tasks.length)this.tasks[e].status="failed",this.tasks[e].output=n}render(){let e=[];for(let n of this.tasks){let i=`${this.getStatusIcon(n.status)} ${n.title}`;if(n.output)i+=`
|
|
2722
2720
|
${n.output}`;e.push(i)}return e.join(`
|
|
2723
|
-
`)}getStatusIcon(e){switch(e){case"pending":return"○";case"running":return"◐";case"completed":return"✓";case"failed":return"✗";default:return"○"}}}function
|
|
2721
|
+
`)}getStatusIcon(e){switch(e){case"pending":return"○";case"running":return"◐";case"completed":return"✓";case"failed":return"✗";default:return"○"}}}function Us(e,n){let r=[];for(let i=0;i<=n.length;i++)r[i]=[i];for(let i=0;i<=e.length;i++)r[0][i]=i;for(let i=1;i<=n.length;i++)for(let s=1;s<=e.length;s++)if(n.charAt(i-1)===e.charAt(s-1))r[i][s]=r[i-1][s-1];else r[i][s]=Math.min(r[i-1][s-1]+1,r[i][s-1]+1,r[i-1][s]+1);return r[n.length][e.length]}function Hs(e,n){let r=Us(e.toLowerCase(),n.toLowerCase()),i=Math.max(e.length,n.length);if(i===0)return 1;return 1-r/i}function Ul(e,n,r=0.5){return n.map((s)=>({command:s,score:Hs(e,s)})).filter((s)=>s.score>=r).sort((s,a)=>a.score-s.score).map((s)=>s.command).slice(0,5)}function nf(e,n){if(n.length===0)return`Unknown command: '${e}'
|
|
2724
2722
|
|
|
2725
2723
|
Run 'ts-cloud --help' to see available commands.`;if(n.length===1)return`Unknown command: '${e}'
|
|
2726
2724
|
|
|
@@ -2728,17 +2726,17 @@ Did you mean: ${n[0]}?`;return`Unknown command: '${e}'
|
|
|
2728
2726
|
|
|
2729
2727
|
Did you mean one of these?
|
|
2730
2728
|
${n.map((r)=>` • ${r}`).join(`
|
|
2731
|
-
`)}`}function
|
|
2732
|
-
`)}function
|
|
2733
|
-
`)}function
|
|
2734
|
-
`)}function
|
|
2729
|
+
`)}`}function of(e,n){return Ul(e,n,0.7).length>0}function sf(e,n){let r=n.find((a)=>a.commands.some((c)=>c.name===e||c.aliases?.includes(e)));if(!r)return"No contextual help available.";let i=[];i.push(`${r.name}`),i.push("─".repeat(r.name.length)),i.push(r.description),i.push(""),i.push("Related commands:");for(let a of r.commands)if(i.push(` ${a.name.padEnd(20)} ${a.description}`),a.aliases&&a.aliases.length>0)i.push(` Aliases: ${a.aliases.join(", ")}`);let s=r.commands.find((a)=>a.name===e||a.aliases?.includes(e));if(s?.examples&&s.examples.length>0){i.push(""),i.push("Examples:");for(let a of s.examples)i.push(` ${a}`)}return i.join(`
|
|
2730
|
+
`)}function af(e,n){let r=[],i=e.toLowerCase();for(let s of n)for(let a of s.commands){let c=a.name.toLowerCase().includes(i),u=a.description.toLowerCase().includes(i),d=a.aliases?.some((m)=>m.toLowerCase().includes(i));if(c||u||d)r.push({command:a,category:s.name})}return r}function cf(e,n,r=10){let i=e.toLowerCase(),s=n.filter((c)=>c.toLowerCase().startsWith(i)),a=n.filter((c)=>c.toLowerCase().includes(i)&&!c.toLowerCase().startsWith(i));return[...s,...a].slice(0,r)}function lf(e,n){let r=e.toLowerCase();return n.filter((i)=>{let s=i.name.toLowerCase().includes(r),a=i.alias?.toLowerCase().includes(r);return s||a})}function df(e){if(e.length===0)return"No matching flags found.";let n=[];for(let r of e){let i=` --${r.name}`;if(r.alias)i+=`, -${r.alias}`;if(i=i.padEnd(30),i+=r.description,r.required)i+=" (required)";n.push(i)}return n.join(`
|
|
2731
|
+
`)}function uf(e){let n=[];if(n.push(`Usage: ts-cloud ${e.name}`),n.push(""),n.push(e.description),e.aliases&&e.aliases.length>0)n.push(""),n.push(`Aliases: ${e.aliases.join(", ")}`);if(e.examples&&e.examples.length>0){n.push(""),n.push("Examples:");for(let r of e.examples)n.push(` ${r}`)}return n.join(`
|
|
2732
|
+
`)}function pf(e,n,r=[]){let i={valid:!0,errors:[],warnings:[],suggestions:[]},[s,...a]=e.split(" ");if(!n.includes(s)){i.valid=!1,i.errors.push(`Unknown command: ${s}`);let c=Ul(s,n);if(c.length>0)i.suggestions.push(...c)}for(let c of r)if(!a.some((u)=>u===`--${c}`||u.startsWith(`--${c}=`)))i.valid=!1,i.errors.push(`Missing required flag: --${c}`);return i}class lp{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[n,...r]=this.parseCommand(e);if(n==="exit"||n==="quit"){this.stop();return}if(n==="help"){this.showHelp();return}if(n==="history"){this.showHistory();return}if(n==="clear"){console.clear();return}let i=this.findCommand(n);if(!i){console.error(`Unknown command: ${n}`),console.log('Type "help" to see available commands.');return}try{await i.handler(r)}catch(s){if(s instanceof Error)console.error(`Command failed: ${s.message}`)}}parseCommand(e){return e.trim().split(/\s+/)}findCommand(e){for(let[n,r]of this.options.commands)if(r.name===e||r.aliases?.includes(e))return r;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 n of e){let r=` ${n.name.padEnd(20)} ${n.description}`;if(n.aliases&&n.aliases.length>0)r+=` (aliases: ${n.aliases.join(", ")})`;console.log(r)}}showHistory(){if(this.history.commands.length===0){console.log("No command history");return}console.log("Command history:"),this.history.commands.forEach((e,n)=>{console.log(` ${(n+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 n=[],r=["help","history","clear","exit","quit"];for(let i of r)if(i.startsWith(e))n.push(i);for(let[i,s]of this.options.commands){if(s.name.startsWith(e))n.push(s.name);if(s.aliases){for(let a of s.aliases)if(a.startsWith(e))n.push(a)}}return n}async loadHistory(){if(!this.options.historyFile)return;try{let e=await import("node:fs/promises"),n=await e.readFile(this.options.historyFile,"utf-8");this.history.commands=n.split(`
|
|
2735
2733
|
`).filter((r)=>r.trim()),this.historyIndex=this.history.commands.length}catch{}}async saveHistory(){if(!this.options.historyFile)return;try{let e=await import("node:fs/promises");await e.writeFile(this.options.historyFile,this.history.commands.join(`
|
|
2736
|
-
`))}catch(e){console.error(`Failed to save history: ${e}`)}}searchHistory(e){return this.history.commands.filter((n)=>n.includes(e))}clearHistory(){this.history.commands=[],this.historyIndex=0}}class
|
|
2737
|
-
`)}importJSON(e){let r=JSON.parse(e).map((i)=>({...i,timestamp:new Date(i.timestamp)}));if(this.entries.push(...r),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}groupByDate(){let e=new Map;for(let n of this.entries){let r=n.timestamp.toISOString().split("T")[0];if(!e.has(r))e.set(r,[]);e.get(r).push(n)}return e}groupByCommand(){let e=new Map;for(let n of this.entries){let r=n.command.split(" ")[0];if(!e.has(r))e.set(r,[]);e.get(r).push(n)}return e}replay(e){return this.getByIndex(e)?.command}getSuggestions(e,n=5){let r=e.toLowerCase(),i=this.entries.filter((s)=>s.command.toLowerCase().startsWith(r)).map((s)=>s.command);return[...new Set(i)].slice(0,n)}analyzePatterns(){let e=new Map,n=new Map;for(let i of this.entries){let s=i.timestamp.getHours(),a=i.timestamp.getDay();e.set(s,(e.get(s)||0)+1),n.set(a,(n.get(a)||0)+1)}let r=this.entries.length>0?this.getSuccessful().length/this.entries.length:0;return{timeOfDay:e,dayOfWeek:n,successRate:r}}}function
|
|
2738
|
-
`)}function
|
|
2739
|
-
`)}class Dl{deployments=new Map;async deploy(e,n){let r=this.generateDeploymentId(),i={id:r,regions:n.regions.map((s)=>({region:s.code,stackName:this.getStackName(e,s.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(r,i);try{let s=n.regions.find((c)=>c.isPrimary)||n.regions[0];await this.deployToRegion(e,s,i);let a=n.regions.filter((c)=>c.code!==s.code);if(await Promise.all(a.map((c)=>this.deployToRegion(e,c,i))),n.globalResources)await this.deployGlobalResources(i,n);if(n.replication)await this.setupReplication(i,n);if(n.failover?.enabled)await this.setupFailover(i,n);return i.status="deployed",i.endTime=new Date,i}catch(s){throw i.status="failed",i.endTime=new Date,s}}async deployToRegion(e,n,r){let i=r.regions.find((s)=>s.region===n.code);if(!i)throw Error(`Region deployment not found: ${n.code}`);i.status="deploying",i.startTime=new Date;try{let s=this.createRegionConfig(e,n);await this.deployStack(i.stackName,s,n.code),i.status="deployed",i.endTime=new Date,i.outputs={stackId:`arn:aws:cloudformation:${n.code}:123456789012:stack/${i.stackName}/guid`,endpoint:`https://${i.stackName}.${n.code}.example.com`}}catch(s){throw i.status="failed",i.endTime=new Date,i.error=s instanceof Error?s.message:String(s),s}}async deployGlobalResources(e,n){let r={};if(n.globalResources?.route53)r.route53=await this.deployRoute53(e,n);if(n.globalResources?.cloudfront)r.cloudfront=await this.deployCloudFront(e,n);if(n.globalResources?.waf)r.waf=await this.deployWAF(e);e.globalResources=r}async deployRoute53(e,n){let r=[],i=[];for(let s of e.regions){if(s.status!=="deployed")continue;let a={id:`health-${s.region}`,endpoint:s.outputs?.endpoint,path:n.failover?.healthCheckPath||"/health",region:s.region};r.push(a);let c={name:"example.com",type:"A",region:s.region,setIdentifier:s.region,healthCheckId:a.id,resourceRecords:[s.outputs?.endpoint]};i.push(c)}return{healthChecks:r,recordSets:i,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(e,n){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:e.regions.filter((i)=>i.status==="deployed").map((i,s)=>{let a=n.regions[s];return{id:`origin-${i.region}`,domainName:i.outputs?.endpoint,weight:a?.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,n){if(n.replication?.s3)await this.setupS3Replication(e);if(n.replication?.dynamodb)await this.setupDynamoDBReplication(e);if(n.replication?.secrets)await this.setupSecretsReplication(e)}async setupS3Replication(e){let n=e.regions.filter((r)=>r.status==="deployed");for(let r=0;r<n.length-1;r++){let i=n[r],s=n[r+1];console.log(`Setting up S3 replication: ${i.region} -> ${s.region}`)}}async setupDynamoDBReplication(e){let n=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up DynamoDB global table in regions: ${n.join(", ")}`)}async setupSecretsReplication(e){let n=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up Secrets Manager replication in regions: ${n.join(", ")}`)}async setupFailover(e,n){let r=e.regions.find((s,a)=>n.regions[a]?.isPrimary)||e.regions[0],i=e.regions.filter((s)=>s.region!==r.region);console.log(`Setting up failover: primary=${r.region}, secondary=${i.map((s)=>s.region).join(", ")}`)}async destroy(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);n.status="rolling-back";try{if(n.globalResources)await this.destroyGlobalResources(n.globalResources);await Promise.all(n.regions.map((r)=>this.destroyRegionStack(r))),this.deployments.delete(e)}catch(r){throw n.status="failed",r}}async destroyGlobalResources(e){if(e.waf)console.log("Destroying WAF resources");if(e.cloudfront)console.log("Destroying CloudFront distribution");if(e.route53)console.log("Destroying Route53 resources")}async destroyRegionStack(e){if(e.status!=="deployed")return;e.status="rolling-back";try{console.log(`Destroying stack ${e.stackName} in ${e.region}`),e.status="pending"}catch(n){throw e.status="failed",e.error=n instanceof Error?n.message:String(n),n}}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getStackName(e,n){return`${e.project.slug}-${n}`}createRegionConfig(e,n){return{...e,infrastructure:{...e.infrastructure}}}async deployStack(e,n,r){console.log(`Deploying stack ${e} to ${r}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var tf=new Dl;class kl{references=[];exports=new Map;addExport(e){let n=`${e.region}:${e.exportName}`;if(!this.exports.has(e.region))this.exports.set(e.region,[]);this.exports.get(e.region).push(e)}getExport(e,n){let r=this.exports.get(e);if(!r)return;return r.find((s)=>s.exportName===n)?.value}createReference(e,n,r,i){let s=`/cross-region/${e}/${r}/${i}`;return this.references.push({sourceRegion:e,targetRegion:n,resourceType:r,resourceId:i,value:s}),s}async resolveReference(e,n){let r=this.references.find((i)=>i.targetRegion===e&&i.value===n);if(!r)throw Error(`Reference not found: ${n}`);return`arn:aws:resource:${r.sourceRegion}:123456789012:${r.resourceType}/${r.resourceId}`}getReferencesForRegion(e){return this.references.filter((n)=>n.sourceRegion===e||n.targetRegion===e)}clear(){this.references=[],this.exports.clear()}}class Nl{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((n)=>n.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 xl{pairs=[];addPair(e){this.pairs.push(e)}getPairedRegion(e){let n=this.pairs.find((r)=>r.primary===e||r.secondary===e);if(!n)return;return n.primary===e?n.secondary:n.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((e)=>e.replicationConfig)}getFailoverPairs(){return this.pairs.filter((e)=>e.failoverConfig?.automatic)}arePaired(e,n){return this.pairs.some((r)=>r.primary===e&&r.secondary===n||r.primary===n&&r.secondary===e)}clear(){this.pairs=[]}}class _l{dependencies=[];addDependency(e){this.dependencies.push(e)}getDependencies(e,n){return this.dependencies.filter((r)=>r.dependentStack===e&&r.dependentRegion===n)}getDependents(e,n){return this.dependencies.filter((r)=>r.dependsOnStack===e&&r.dependsOnRegion===n)}hasDependencies(e,n){return this.getDependencies(e,n).length>0}getDeploymentOrder(e){let n=new Set,r=[],i=(s)=>{let a=`${s.name}:${s.region}`;if(n.has(a))return;n.add(a);let c=this.getDependencies(s.name,s.region);for(let u of c)i({name:u.dependsOnStack,region:u.dependsOnRegion});r.push(s)};for(let s of e)i(s);return r}detectCircularDependencies(){let e=new Set,n=new Set,r=(i,s)=>{let a=`${i}:${s}`;if(n.has(a))return!0;if(e.has(a))return!1;e.add(a),n.add(a);let c=this.getDependencies(i,s);for(let u of c)if(r(u.dependsOnStack,u.dependsOnRegion))return!0;return n.delete(a),!1};for(let i of this.dependencies)if(r(i.dependentStack,i.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var rf=new kl,nf=new Nl,of=new xl,sf=new _l;var ct=[{code:"us-east-1",name:"US East (N. Virginia)",location:"Virginia, USA",launchYear:2006,availabilityZones:6,localZones:16,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO","FedRAMP"]},{code:"us-east-2",name:"US East (Ohio)",location:"Ohio, USA",launchYear:2016,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"us-west-1",name:"US West (N. California)",location:"California, USA",launchYear:2009,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"us-west-2",name:"US West (Oregon)",location:"Oregon, USA",launchYear:2011,availabilityZones:4,localZones:2,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"eu-west-1",name:"Europe (Ireland)",location:"Dublin, Ireland",launchYear:2007,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1.05},compliance:["PCI-DSS","GDPR","SOC","ISO"]},{code:"eu-central-1",name:"Europe (Frankfurt)",location:"Frankfurt, Germany",launchYear:2014,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.1},compliance:["PCI-DSS","GDPR","SOC","ISO"]},{code:"ap-southeast-1",name:"Asia Pacific (Singapore)",location:"Singapore",launchYear:2010,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.12},compliance:["PCI-DSS","SOC","ISO","MTCS"]},{code:"ap-northeast-1",name:"Asia Pacific (Tokyo)",location:"Tokyo, Japan",launchYear:2011,availabilityZones:4,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.15},compliance:["PCI-DSS","SOC","ISO"]}];function Wi(e){return ct.find((n)=>n.code===e)}function af(){return ct}function cf(e){let n=e.toLowerCase();return ct.filter((r)=>r.location.toLowerCase().includes(n))}function lf(e){return ct.filter((n)=>n.compliance.includes(e))}function df(e){return ct.filter((n)=>n.pricing.tier===e)}function uf(e){return ct.some((n)=>n.code===e)}function pf(e){if(e.continent==="North America")return Wi("us-east-1");if(e.continent==="Europe")return Wi("eu-west-1");if(e.continent==="Asia")return Wi("ap-southeast-1");return Wi("us-east-1")}function mf(e){let n=[...ct];if(e.compliance)n=n.filter((r)=>e.compliance.every((i)=>r.compliance.includes(i)));if(e.requiredServices)n=n.filter((r)=>e.requiredServices.every((i)=>r.services[i]));if(e.pricingSensitive)n.sort((r,i)=>r.pricing.multiplier-i.pricing.multiplier);return n.slice(0,5)}function gf(e){let n=Wi(e);if(!n)throw Error(`Invalid region: ${e}`);let r=[];for(let i of ct){if(i.code===e)continue;let s=us(n,i),a=ds(n,i);r.push({primary:n,secondary:i,distance:s,sameContinent:a})}return r.sort((i,s)=>{if(i.sameContinent!==s.sameContinent)return i.sameContinent?1:-1;return i.distance-s.distance}),r.slice(0,3)}function us(e,n){let r={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},i=Qe(e.location),s=Qe(n.location);return Math.abs((r[i]||0)-(r[s]||0))}function ds(e,n){return Qe(e.location)===Qe(n.location)}function Qe(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 tp(e){return`${e.name} (${e.code})`}function ff(e){return e.map((n)=>tp(n)).join(`
|
|
2740
|
-
`)}function hf(){let e={total:ct.length,byContinent:{},byPricingTier:{}};for(let n of ct){let r=Qe(n.location);e.byContinent[r]=(e.byContinent[r]||0)+1,e.byPricingTier[n.pricing.tier]=(e.byPricingTier[n.pricing.tier]||0)+1}return e}class Ol{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((n)=>n.alias===e)}listAccounts(){return Array.from(this.accounts.values())}getAccountsByRole(e){return Array.from(this.accounts.values()).filter((n)=>n.role===e)}createCrossAccountRole(e,n,r,i,s){let a={roleArn:`arn:aws:iam::${n}:role/${r}`,roleName:r,sourceAccountId:e,targetAccountId:n,permissions:i,externalId:s?.externalId,sessionDuration:s?.sessionDuration||3600};return this.crossAccountRoles.push(a),a}getAssumeRolePolicyDocument(e,n){let r={Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e}:root`},Action:"sts:AssumeRole"}]};if(n)r.Statement[0].Condition={StringEquals:{"sts:ExternalId":n}};return r}generateCrossAccountPolicy(e){return{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e,Resource:"*"}]}}mapEnvironmentToAccount(e,n,r){this.accountMappings.push({environment:e,accountId:n,region:r})}getAccountForEnvironment(e){return this.accountMappings.find((n)=>n.environment===e)}async assumeRole(e,n,r){return console.log(`Assuming role: ${e} with session: ${n}`),{accessKeyId:"AKIAIOSFODNN7EXAMPLE",secretAccessKey:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",sessionToken:"token",expiration:new Date(Date.now()+3600000)}}async getCredentialsForAccount(e){let n=this.accounts.get(e);if(!n)throw Error(`Account not found: ${e}`);if(n.assumeRoleArn){let r=await this.assumeRole(n.assumeRoleArn,`ts-cloud-${Date.now()}`);return{accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken}}throw Error("No credentials available for account")}listCrossAccountRoles(){return[...this.crossAccountRoles]}getCrossAccountRolesForAccount(e){return this.crossAccountRoles.filter((n)=>n.sourceAccountId===e||n.targetAccountId===e)}async validateAccountAccess(e){try{let n=await this.getCredentialsForAccount(e);return console.log(`Validating access to account: ${e}`),!0}catch{return!1}}async getConsolidatedBilling(){let e={};for(let r of this.accounts.values())e[r.id]=Math.random()*1000;return{totalCost:Object.values(e).reduce((r,i)=>r+i,0),byAccount:e}}clear(){this.accounts.clear(),this.crossAccountRoles=[],this.accountMappings=[]}}class $l{organizationId;organizationalUnits=new Map;getOrganizationId(){return this.organizationId}setOrganizationId(e){this.organizationId=e}createOrganizationalUnit(e,n){let r={id:`ou-${Date.now()}`,name:e,parentId:n,accounts:[]};return this.organizationalUnits.set(r.id,r),r}getOrganizationalUnit(e){return this.organizationalUnits.get(e)}listOrganizationalUnits(){return Array.from(this.organizationalUnits.values())}addAccountToOU(e,n){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);if(!r.accounts.includes(n))r.accounts.push(n)}removeAccountFromOU(e,n){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);r.accounts=r.accounts.filter((i)=>i!==n)}getAccountsInOU(e){let n=this.organizationalUnits.get(e);if(!n)return[];return[...n.accounts]}applyServiceControlPolicy(e,n){return{id:`scp-${Date.now()}`,name:"Custom SCP",targetId:e,policyDocument:n}}clear(){this.organizationId=void 0,this.organizationalUnits.clear()}}var yf=new Ol,bf=new $l;var rp={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"}]}},Sf={denyRootAccess:{name:"Deny Root User Access",description:"Prevent root user from performing any actions",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyRootUser",Effect:"Deny",Action:"*",Resource:"*",Condition:{StringLike:{"aws:PrincipalArn":"arn:aws:iam::*:root"}}}]}},requireMFA:{name:"Require MFA for All Actions",description:"Require MFA for console and API access",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"RequireMFA",Effect:"Deny",Action:"*",Resource:"*",Condition:{BoolIfExists:{"aws:MultiFactorAuthPresent":"false"}}}]}},denyRegions:{name:"Deny Access to Non-Approved Regions",description:"Restrict operations to specific regions",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyNonApprovedRegions",Effect:"Deny",NotAction:["iam:*","organizations:*","route53:*","cloudfront:*","support:*","s3:*"],Resource:"*",Condition:{StringNotEquals:{"aws:RequestedRegion":["us-east-1","us-west-2"]}}}]}},preventLeaving:{name:"Prevent Leaving Organization",description:"Prevent accounts from leaving the organization",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"PreventLeaving",Effect:"Deny",Action:"organizations:LeaveOrganization",Resource:"*"}]}},denyS3Unencrypted:{name:"Deny Unencrypted S3 Uploads",description:"Require encryption for all S3 uploads",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyUnencryptedS3Uploads",Effect:"Deny",Action:"s3:PutObject",Resource:"*",Condition:{StringNotEquals:{"s3:x-amz-server-side-encryption":["AES256","aws:kms"]}}}]}}},vf={deploymentRole:{name:"CrossAccountDeploymentRole",description:"Role for deploying infrastructure from CI/CD",permissions:["cloudformation:*","s3:*","ec2:*","ecs:*","lambda:*","iam:GetRole","iam:PassRole","logs:*","events:*"]},readOnlyRole:{name:"CrossAccountReadOnlyRole",description:"Read-only access for monitoring and auditing",permissions:["cloudformation:Describe*","cloudformation:List*","ec2:Describe*","ecs:Describe*","lambda:Get*","lambda:List*","s3:Get*","s3:List*","logs:Get*","logs:Describe*"]},securityAuditRole:{name:"CrossAccountSecurityAuditRole",description:"Security audit and compliance checks",permissions:["iam:Get*","iam:List*","iam:Generate*","access-analyzer:*","guardduty:Get*","guardduty:List*","securityhub:Get*","securityhub:List*","config:Describe*","config:Get*","config:List*"]},breakGlassRole:{name:"CrossAccountBreakGlassRole",description:"Emergency access role (use with caution)",permissions:["*"]}};function Cf(e){return rp[e]}function Tf(e,n){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:"*"}]}}],...n&&{ManagedPolicyArns:n},MaxSessionDuration:e.sessionDuration||3600,Tags:[{Key:"ManagedBy",Value:"TS-Cloud"},{Key:"SourceAccount",Value:e.sourceAccountId}]}}}function Ef(e){let n=[],r=[],i=e.accounts.filter((d)=>d.role==="management");if(i.length===0)n.push("No management account defined");if(i.length>1)n.push("Multiple management accounts defined");let s=e.accounts.map((d)=>d.email),a=s.filter((d,m)=>s.indexOf(d)!==m);if(a.length>0)n.push(`Duplicate email addresses: ${a.join(", ")}`);let c=e.accounts.map((d)=>d.alias),u=c.filter((d,m)=>c.indexOf(d)!==m);if(u.length>0)n.push(`Duplicate aliases: ${u.join(", ")}`);if(!e.accounts.some((d)=>d.role==="security"))r.push("No dedicated security account - consider adding one for audit logs");if(e.accounts.length<3)r.push("Less than 3 accounts - consider separating environments");if(!e.accounts.some((d)=>d.role==="production"))r.push("No production account defined");return{valid:n.length===0,errors:n,warnings:r}}function wf(e){let n=[];if(n.push(`${e.name}`),n.push("─".repeat(e.name.length)),n.push(e.description),n.push(""),e.organizationalUnits){n.push("Organizational Units:");for(let r of e.organizationalUnits){let i=r.parent?" └─ ":" ";n.push(`${i}${r.name}`)}n.push("")}n.push("Accounts:");for(let r of e.accounts)n.push(` ${r.alias.padEnd(20)} ${r.role.padEnd(15)} ${r.email}`),n.push(` ${"".padEnd(20)} ${r.description}`),n.push("");return n.join(`
|
|
2741
|
-
`)}function
|
|
2734
|
+
`))}catch(e){console.error(`Failed to save history: ${e}`)}}searchHistory(e){return this.history.commands.filter((n)=>n.includes(e))}clearHistory(){this.history.commands=[],this.historyIndex=0}}class dp{variables=new Map;workingDirectory=process.cwd();set(e,n){this.variables.set(e,n)}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 up{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 pp{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 n=e.toLowerCase();return this.entries.filter((r)=>r.command.toLowerCase().includes(n))}searchByDate(e,n){return this.entries.filter((r)=>r.timestamp>=e&&r.timestamp<=n)}getSuccessful(){return this.entries.filter((e)=>e.success)}getFailed(){return this.entries.filter((e)=>!e.success)}getMostUsed(e=10){let n=new Map;for(let r of this.entries){let i=r.command.split(" ")[0];n.set(i,(n.get(i)||0)+1)}return Array.from(n.entries()).map(([r,i])=>({command:r,count:i})).sort((r,i)=>i.count-r.count).slice(0,e)}getStats(){let e=this.entries.length,n=this.entries.filter((u)=>u.success).length,r=this.entries.filter((u)=>!u.success).length,i=this.entries.filter((u)=>u.duration!==void 0),s=i.length>0?i.reduce((u,d)=>u+(d.duration||0),0)/i.length:0,a=this.getMostUsed(1),c=a.length>0?a[0].command:"N/A";return{total:e,successful:n,failed:r,averageDuration:s,mostUsed:c}}clear(){this.entries=[]}getByIndex(e){if(e<0||e>=this.entries.length)return;return this.entries[e]}removeByIndex(e){if(e>=0&&e<this.entries.length)this.entries.splice(e,1)}async save(){if(!this.persistFile)return;try{let e=await import("node:fs/promises"),n=JSON.stringify(this.entries,null,2);await e.writeFile(this.persistFile,n,"utf-8")}catch(e){throw Error(`Failed to save history: ${e}`)}}async load(){if(!this.persistFile)return;try{let e=await import("node:fs/promises"),n=await e.readFile(this.persistFile,"utf-8"),r=JSON.parse(n);this.entries=r.map((i)=>({...i,timestamp:new Date(i.timestamp)}))}catch{this.entries=[]}}exportJSON(){return JSON.stringify(this.entries,null,2)}exportCSV(){return["Timestamp,Command,Success,Duration",...this.entries.map((r)=>[r.timestamp.toISOString(),`"${r.command.replace(/"/g,'""')}"`,r.success,r.duration||""].join(","))].join(`
|
|
2735
|
+
`)}importJSON(e){let r=JSON.parse(e).map((i)=>({...i,timestamp:new Date(i.timestamp)}));if(this.entries.push(...r),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}groupByDate(){let e=new Map;for(let n of this.entries){let r=n.timestamp.toISOString().split("T")[0];if(!e.has(r))e.set(r,[]);e.get(r).push(n)}return e}groupByCommand(){let e=new Map;for(let n of this.entries){let r=n.command.split(" ")[0];if(!e.has(r))e.set(r,[]);e.get(r).push(n)}return e}replay(e){return this.getByIndex(e)?.command}getSuggestions(e,n=5){let r=e.toLowerCase(),i=this.entries.filter((s)=>s.command.toLowerCase().startsWith(r)).map((s)=>s.command);return[...new Set(i)].slice(0,n)}analyzePatterns(){let e=new Map,n=new Map;for(let i of this.entries){let s=i.timestamp.getHours(),a=i.timestamp.getDay();e.set(s,(e.get(s)||0)+1),n.set(a,(n.get(a)||0)+1)}let r=this.entries.length>0?this.getSuccessful().length/this.entries.length:0;return{timeOfDay:e,dayOfWeek:n,successRate:r}}}function mf(e,n={}){let{maxWidth:r=100}=n;if(e.length===0)return"No command history";let i=[];for(let s=0;s<e.length;s++){let a=e[s],c=(s+1).toString().padStart(4),u=a.timestamp.toLocaleString(),d=a.success?"✓":"✗",m=a.command;if(m.length>r-30)m=m.substring(0,r-33)+"...";let p=`${c} ${u} ${d} ${m}`;if(a.duration)p+=` (${a.duration}ms)`;i.push(p)}return i.join(`
|
|
2736
|
+
`)}function gf(e){let n=[];return n.push("Command History Statistics"),n.push("─".repeat(30)),n.push(`Total commands: ${e.total}`),n.push(`Successful: ${e.successful}`),n.push(`Failed: ${e.failed}`),n.push(`Success rate: ${(e.successful/e.total*100).toFixed(1)}%`),n.push(`Average duration: ${e.averageDuration.toFixed(0)}ms`),n.push(`Most used: ${e.mostUsed}`),n.join(`
|
|
2737
|
+
`)}class Bl{deployments=new Map;async deploy(e,n){let r=this.generateDeploymentId(),i={id:r,regions:n.regions.map((s)=>({region:s.code,stackName:this.getStackName(e,s.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(r,i);try{let s=n.regions.find((c)=>c.isPrimary)||n.regions[0];await this.deployToRegion(e,s,i);let a=n.regions.filter((c)=>c.code!==s.code);if(await Promise.all(a.map((c)=>this.deployToRegion(e,c,i))),n.globalResources)await this.deployGlobalResources(i,n);if(n.replication)await this.setupReplication(i,n);if(n.failover?.enabled)await this.setupFailover(i,n);return i.status="deployed",i.endTime=new Date,i}catch(s){throw i.status="failed",i.endTime=new Date,s}}async deployToRegion(e,n,r){let i=r.regions.find((s)=>s.region===n.code);if(!i)throw Error(`Region deployment not found: ${n.code}`);i.status="deploying",i.startTime=new Date;try{let s=this.createRegionConfig(e,n);await this.deployStack(i.stackName,s,n.code),i.status="deployed",i.endTime=new Date,i.outputs={stackId:`arn:aws:cloudformation:${n.code}:123456789012:stack/${i.stackName}/guid`,endpoint:`https://${i.stackName}.${n.code}.example.com`}}catch(s){throw i.status="failed",i.endTime=new Date,i.error=s instanceof Error?s.message:String(s),s}}async deployGlobalResources(e,n){let r={};if(n.globalResources?.route53)r.route53=await this.deployRoute53(e,n);if(n.globalResources?.cloudfront)r.cloudfront=await this.deployCloudFront(e,n);if(n.globalResources?.waf)r.waf=await this.deployWAF(e);e.globalResources=r}async deployRoute53(e,n){let r=[],i=[];for(let s of e.regions){if(s.status!=="deployed")continue;let a={id:`health-${s.region}`,endpoint:s.outputs?.endpoint,path:n.failover?.healthCheckPath||"/health",region:s.region};r.push(a);let c={name:"example.com",type:"A",region:s.region,setIdentifier:s.region,healthCheckId:a.id,resourceRecords:[s.outputs?.endpoint]};i.push(c)}return{healthChecks:r,recordSets:i,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(e,n){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:e.regions.filter((i)=>i.status==="deployed").map((i,s)=>{let a=n.regions[s];return{id:`origin-${i.region}`,domainName:i.outputs?.endpoint,weight:a?.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,n){if(n.replication?.s3)await this.setupS3Replication(e);if(n.replication?.dynamodb)await this.setupDynamoDBReplication(e);if(n.replication?.secrets)await this.setupSecretsReplication(e)}async setupS3Replication(e){let n=e.regions.filter((r)=>r.status==="deployed");for(let r=0;r<n.length-1;r++){let i=n[r],s=n[r+1];console.log(`Setting up S3 replication: ${i.region} -> ${s.region}`)}}async setupDynamoDBReplication(e){let n=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up DynamoDB global table in regions: ${n.join(", ")}`)}async setupSecretsReplication(e){let n=e.regions.filter((r)=>r.status==="deployed").map((r)=>r.region);console.log(`Setting up Secrets Manager replication in regions: ${n.join(", ")}`)}async setupFailover(e,n){let r=e.regions.find((s,a)=>n.regions[a]?.isPrimary)||e.regions[0],i=e.regions.filter((s)=>s.region!==r.region);console.log(`Setting up failover: primary=${r.region}, secondary=${i.map((s)=>s.region).join(", ")}`)}async destroy(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);n.status="rolling-back";try{if(n.globalResources)await this.destroyGlobalResources(n.globalResources);await Promise.all(n.regions.map((r)=>this.destroyRegionStack(r))),this.deployments.delete(e)}catch(r){throw n.status="failed",r}}async destroyGlobalResources(e){if(e.waf)console.log("Destroying WAF resources");if(e.cloudfront)console.log("Destroying CloudFront distribution");if(e.route53)console.log("Destroying Route53 resources")}async destroyRegionStack(e){if(e.status!=="deployed")return;e.status="rolling-back";try{console.log(`Destroying stack ${e.stackName} in ${e.region}`),e.status="pending"}catch(n){throw e.status="failed",e.error=n instanceof Error?n.message:String(n),n}}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getStackName(e,n){return`${e.project.slug}-${n}`}createRegionConfig(e,n){return{...e,infrastructure:{...e.infrastructure}}}async deployStack(e,n,r){console.log(`Deploying stack ${e} to ${r}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var ff=new Bl;class Fl{references=[];exports=new Map;addExport(e){let n=`${e.region}:${e.exportName}`;if(!this.exports.has(e.region))this.exports.set(e.region,[]);this.exports.get(e.region).push(e)}getExport(e,n){let r=this.exports.get(e);if(!r)return;return r.find((s)=>s.exportName===n)?.value}createReference(e,n,r,i){let s=`/cross-region/${e}/${r}/${i}`;return this.references.push({sourceRegion:e,targetRegion:n,resourceType:r,resourceId:i,value:s}),s}async resolveReference(e,n){let r=this.references.find((i)=>i.targetRegion===e&&i.value===n);if(!r)throw Error(`Reference not found: ${n}`);return`arn:aws:resource:${r.sourceRegion}:123456789012:${r.resourceType}/${r.resourceId}`}getReferencesForRegion(e){return this.references.filter((n)=>n.sourceRegion===e||n.targetRegion===e)}clear(){this.references=[],this.exports.clear()}}class jl{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((n)=>n.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 Vl{pairs=[];addPair(e){this.pairs.push(e)}getPairedRegion(e){let n=this.pairs.find((r)=>r.primary===e||r.secondary===e);if(!n)return;return n.primary===e?n.secondary:n.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((e)=>e.replicationConfig)}getFailoverPairs(){return this.pairs.filter((e)=>e.failoverConfig?.automatic)}arePaired(e,n){return this.pairs.some((r)=>r.primary===e&&r.secondary===n||r.primary===n&&r.secondary===e)}clear(){this.pairs=[]}}class zl{dependencies=[];addDependency(e){this.dependencies.push(e)}getDependencies(e,n){return this.dependencies.filter((r)=>r.dependentStack===e&&r.dependentRegion===n)}getDependents(e,n){return this.dependencies.filter((r)=>r.dependsOnStack===e&&r.dependsOnRegion===n)}hasDependencies(e,n){return this.getDependencies(e,n).length>0}getDeploymentOrder(e){let n=new Set,r=[],i=(s)=>{let a=`${s.name}:${s.region}`;if(n.has(a))return;n.add(a);let c=this.getDependencies(s.name,s.region);for(let u of c)i({name:u.dependsOnStack,region:u.dependsOnRegion});r.push(s)};for(let s of e)i(s);return r}detectCircularDependencies(){let e=new Set,n=new Set,r=(i,s)=>{let a=`${i}:${s}`;if(n.has(a))return!0;if(e.has(a))return!1;e.add(a),n.add(a);let c=this.getDependencies(i,s);for(let u of c)if(r(u.dependsOnStack,u.dependsOnRegion))return!0;return n.delete(a),!1};for(let i of this.dependencies)if(r(i.dependentStack,i.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var hf=new Fl,yf=new jl,bf=new Vl,Sf=new zl;var dt=[{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 Yi(e){return dt.find((n)=>n.code===e)}function vf(){return dt}function Cf(e){let n=e.toLowerCase();return dt.filter((r)=>r.location.toLowerCase().includes(n))}function Tf(e){return dt.filter((n)=>n.compliance.includes(e))}function Ef(e){return dt.filter((n)=>n.pricing.tier===e)}function wf(e){return dt.some((n)=>n.code===e)}function Af(e){if(e.continent==="North America")return Yi("us-east-1");if(e.continent==="Europe")return Yi("eu-west-1");if(e.continent==="Asia")return Yi("ap-southeast-1");return Yi("us-east-1")}function Rf(e){let n=[...dt];if(e.compliance)n=n.filter((r)=>e.compliance.every((i)=>r.compliance.includes(i)));if(e.requiredServices)n=n.filter((r)=>e.requiredServices.every((i)=>r.services[i]));if(e.pricingSensitive)n.sort((r,i)=>r.pricing.multiplier-i.pricing.multiplier);return n.slice(0,5)}function If(e){let n=Yi(e);if(!n)throw Error(`Invalid region: ${e}`);let r=[];for(let i of dt){if(i.code===e)continue;let s=js(n,i),a=Ks(n,i);r.push({primary:n,secondary:i,distance:s,sameContinent:a})}return r.sort((i,s)=>{if(i.sameContinent!==s.sameContinent)return i.sameContinent?1:-1;return i.distance-s.distance}),r.slice(0,3)}function js(e,n){let r={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},i=Ye(e.location),s=Ye(n.location);return Math.abs((r[i]||0)-(r[s]||0))}function Ks(e,n){return Ye(e.location)===Ye(n.location)}function Ye(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 mp(e){return`${e.name} (${e.code})`}function Pf(e){return e.map((n)=>mp(n)).join(`
|
|
2738
|
+
`)}function Df(){let e={total:dt.length,byContinent:{},byPricingTier:{}};for(let n of dt){let r=Ye(n.location);e.byContinent[r]=(e.byContinent[r]||0)+1,e.byPricingTier[n.pricing.tier]=(e.byPricingTier[n.pricing.tier]||0)+1}return e}class Hl{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((n)=>n.alias===e)}listAccounts(){return Array.from(this.accounts.values())}getAccountsByRole(e){return Array.from(this.accounts.values()).filter((n)=>n.role===e)}createCrossAccountRole(e,n,r,i,s){let a={roleArn:`arn:aws:iam::${n}:role/${r}`,roleName:r,sourceAccountId:e,targetAccountId:n,permissions:i,externalId:s?.externalId,sessionDuration:s?.sessionDuration||3600};return this.crossAccountRoles.push(a),a}getAssumeRolePolicyDocument(e,n){let r={Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${e}:root`},Action:"sts:AssumeRole"}]};if(n)r.Statement[0].Condition={StringEquals:{"sts:ExternalId":n}};return r}generateCrossAccountPolicy(e){return{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:e,Resource:"*"}]}}mapEnvironmentToAccount(e,n,r){this.accountMappings.push({environment:e,accountId:n,region:r})}getAccountForEnvironment(e){return this.accountMappings.find((n)=>n.environment===e)}async assumeRole(e,n,r){return console.log(`Assuming role: ${e} with session: ${n}`),{accessKeyId:"AKIAIOSFODNN7EXAMPLE",secretAccessKey:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",sessionToken:"token",expiration:new Date(Date.now()+3600000)}}async getCredentialsForAccount(e){let n=this.accounts.get(e);if(!n)throw Error(`Account not found: ${e}`);if(n.assumeRoleArn){let r=await this.assumeRole(n.assumeRoleArn,`ts-cloud-${Date.now()}`);return{accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken}}throw Error("No credentials available for account")}listCrossAccountRoles(){return[...this.crossAccountRoles]}getCrossAccountRolesForAccount(e){return this.crossAccountRoles.filter((n)=>n.sourceAccountId===e||n.targetAccountId===e)}async validateAccountAccess(e){try{let n=await this.getCredentialsForAccount(e);return console.log(`Validating access to account: ${e}`),!0}catch{return!1}}async getConsolidatedBilling(){let e={};for(let r of this.accounts.values())e[r.id]=Math.random()*1000;return{totalCost:Object.values(e).reduce((r,i)=>r+i,0),byAccount:e}}clear(){this.accounts.clear(),this.crossAccountRoles=[],this.accountMappings=[]}}class Gl{organizationId;organizationalUnits=new Map;getOrganizationId(){return this.organizationId}setOrganizationId(e){this.organizationId=e}createOrganizationalUnit(e,n){let r={id:`ou-${Date.now()}`,name:e,parentId:n,accounts:[]};return this.organizationalUnits.set(r.id,r),r}getOrganizationalUnit(e){return this.organizationalUnits.get(e)}listOrganizationalUnits(){return Array.from(this.organizationalUnits.values())}addAccountToOU(e,n){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);if(!r.accounts.includes(n))r.accounts.push(n)}removeAccountFromOU(e,n){let r=this.organizationalUnits.get(e);if(!r)throw Error(`Organizational unit not found: ${e}`);r.accounts=r.accounts.filter((i)=>i!==n)}getAccountsInOU(e){let n=this.organizationalUnits.get(e);if(!n)return[];return[...n.accounts]}applyServiceControlPolicy(e,n){return{id:`scp-${Date.now()}`,name:"Custom SCP",targetId:e,policyDocument:n}}clear(){this.organizationId=void 0,this.organizationalUnits.clear()}}var kf=new Hl,Nf=new Gl;var gp={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"}]}},xf={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"]}}}]}}},_f={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 Of(e){return gp[e]}function $f(e,n){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:"*"}]}}],...n&&{ManagedPolicyArns:n},MaxSessionDuration:e.sessionDuration||3600,Tags:[{Key:"ManagedBy",Value:"TS-Cloud"},{Key:"SourceAccount",Value:e.sourceAccountId}]}}}function Lf(e){let n=[],r=[],i=e.accounts.filter((d)=>d.role==="management");if(i.length===0)n.push("No management account defined");if(i.length>1)n.push("Multiple management accounts defined");let s=e.accounts.map((d)=>d.email),a=s.filter((d,m)=>s.indexOf(d)!==m);if(a.length>0)n.push(`Duplicate email addresses: ${a.join(", ")}`);let c=e.accounts.map((d)=>d.alias),u=c.filter((d,m)=>c.indexOf(d)!==m);if(u.length>0)n.push(`Duplicate aliases: ${u.join(", ")}`);if(!e.accounts.some((d)=>d.role==="security"))r.push("No dedicated security account - consider adding one for audit logs");if(e.accounts.length<3)r.push("Less than 3 accounts - consider separating environments");if(!e.accounts.some((d)=>d.role==="production"))r.push("No production account defined");return{valid:n.length===0,errors:n,warnings:r}}function Mf(e){let n=[];if(n.push(`${e.name}`),n.push("─".repeat(e.name.length)),n.push(e.description),n.push(""),e.organizationalUnits){n.push("Organizational Units:");for(let r of e.organizationalUnits){let i=r.parent?" └─ ":" ";n.push(`${i}${r.name}`)}n.push("")}n.push("Accounts:");for(let r of e.accounts)n.push(` ${r.alias.padEnd(20)} ${r.role.padEnd(15)} ${r.email}`),n.push(` ${"".padEnd(20)} ${r.description}`),n.push("");return n.join(`
|
|
2739
|
+
`)}function Uf(e={}){let{workflowName:n="Deploy",trigger:r="push",branches:i=["main"],environments:s=["production"],awsRegion:a="us-east-1",awsRole:c,bunVersion:u="latest",deployCommand:d="bun run cloud deploy",testCommand:m="bun test",buildCommand:p="bun run build"}=e,g=!!c;return`name: ${n}
|
|
2742
2740
|
|
|
2743
2741
|
on:
|
|
2744
2742
|
${r}:
|
|
@@ -2807,7 +2805,7 @@ jobs:
|
|
|
2807
2805
|
|
|
2808
2806
|
- name: Post-deployment tests
|
|
2809
2807
|
run: bun run cloud test:smoke
|
|
2810
|
-
`}function
|
|
2808
|
+
`}function Bf(e){let{environments:n,awsRegion:r="us-east-1",awsRole:i}=e,s=!!i;return`name: Multi-Environment Deploy
|
|
2811
2809
|
|
|
2812
2810
|
on:
|
|
2813
2811
|
push:
|
|
@@ -2863,7 +2861,7 @@ ${n.map((a,c)=>` ${c>0?"elif":"if"} [[ "\${{ github.ref }}" == "refs/he
|
|
|
2863
2861
|
|
|
2864
2862
|
- name: Deploy
|
|
2865
2863
|
run: bun run cloud deploy --env=\${{ needs.determine-environment.outputs.environment }}
|
|
2866
|
-
`}function
|
|
2864
|
+
`}function Ff(e={}){let{awsRegion:n="us-east-1",awsRole:r,ttl:i=24}=e,s=!!r;return`name: PR Preview Environment
|
|
2867
2865
|
|
|
2868
2866
|
on:
|
|
2869
2867
|
pull_request:
|
|
@@ -2968,7 +2966,7 @@ jobs:
|
|
|
2968
2966
|
bun run cloud env:preview --destroy \\
|
|
2969
2967
|
--branch=\${{ github.head_ref }} \\
|
|
2970
2968
|
--pr=\${{ github.event.pull_request.number }}
|
|
2971
|
-
`}function
|
|
2969
|
+
`}function jf(e){let{schedule:n,environment:r,awsRegion:i="us-east-1",awsRole:s}=e;return`name: Scheduled Deployment
|
|
2972
2970
|
|
|
2973
2971
|
on:
|
|
2974
2972
|
schedule:
|
|
@@ -3010,7 +3008,7 @@ jobs:
|
|
|
3010
3008
|
|
|
3011
3009
|
- name: Deploy
|
|
3012
3010
|
run: bun run cloud deploy --env=\${{ env.ENVIRONMENT }}
|
|
3013
|
-
`}function
|
|
3011
|
+
`}function Vf(e){let{matrix:n,awsRole:r}=e,i=!!r;return`name: Matrix Deployment
|
|
3014
3012
|
|
|
3015
3013
|
on:
|
|
3016
3014
|
workflow_dispatch:
|
|
@@ -3057,7 +3055,7 @@ ${n.map((s)=>` - environment: ${s.environment}
|
|
|
3057
3055
|
|
|
3058
3056
|
- name: Deploy to \${{ matrix.environment }} (\${{ matrix.region }})
|
|
3059
3057
|
run: bun run cloud deploy --env=\${{ matrix.environment }} --region=\${{ matrix.region }}
|
|
3060
|
-
`}function
|
|
3058
|
+
`}function zf(e={}){let{stages:n=["test","build","deploy"],environments:r=["production"],awsRegion:i="us-east-1",dockerImage:s="oven/bun:latest",deployCommand:a="bun run cloud deploy",testCommand:c="bun test",buildCommand:u="bun run build"}=e;return`stages:
|
|
3061
3059
|
${n.map((d)=>` - ${d}`).join(`
|
|
3062
3060
|
`)}
|
|
3063
3061
|
|
|
@@ -3105,7 +3103,7 @@ deploy:
|
|
|
3105
3103
|
only:
|
|
3106
3104
|
- main
|
|
3107
3105
|
when: manual
|
|
3108
|
-
`}function
|
|
3106
|
+
`}function Hf(e){let{environments:n,awsRegion:r="us-east-1"}=e,i=n.map((s)=>`
|
|
3109
3107
|
deploy:${s.name}:
|
|
3110
3108
|
stage: deploy
|
|
3111
3109
|
script:
|
|
@@ -3146,7 +3144,7 @@ build:
|
|
|
3146
3144
|
paths:
|
|
3147
3145
|
- dist/
|
|
3148
3146
|
${i}
|
|
3149
|
-
`}function
|
|
3147
|
+
`}function Gf(e={}){let{awsRegion:n="us-east-1",ttl:r=24}=e;return`stages:
|
|
3150
3148
|
- build
|
|
3151
3149
|
- deploy
|
|
3152
3150
|
- cleanup
|
|
@@ -3191,7 +3189,7 @@ cleanup:preview:
|
|
|
3191
3189
|
when: manual
|
|
3192
3190
|
only:
|
|
3193
3191
|
- merge_requests
|
|
3194
|
-
`}function
|
|
3192
|
+
`}function qf(e){let{environment:n,awsRegion:r="us-east-1"}=e;return`stages:
|
|
3195
3193
|
- deploy
|
|
3196
3194
|
|
|
3197
3195
|
variables:
|
|
@@ -3210,7 +3208,7 @@ deploy:scheduled:
|
|
|
3210
3208
|
name: \${ENVIRONMENT}
|
|
3211
3209
|
only:
|
|
3212
3210
|
- schedules
|
|
3213
|
-
`}function
|
|
3211
|
+
`}function Wf(e){let{environments:n,awsRegion:r="us-east-1"}=e,i=n.map((s)=>`
|
|
3214
3212
|
deploy:${s}:
|
|
3215
3213
|
stage: deploy
|
|
3216
3214
|
script:
|
|
@@ -3231,7 +3229,7 @@ variables:
|
|
|
3231
3229
|
default:
|
|
3232
3230
|
image: oven/bun:latest
|
|
3233
3231
|
${i}
|
|
3234
|
-
`}function
|
|
3232
|
+
`}function Kf(e={}){let{awsRegion:n="us-east-1",dockerImage:r="oven/bun:latest",deployCommand:i="bun run cloud deploy",testCommand:s="bun test",buildCommand:a="bun run build",workflows:c=!0}=e;return`version: 2.1
|
|
3235
3233
|
|
|
3236
3234
|
orbs:
|
|
3237
3235
|
aws-cli: circleci/aws-cli@4.0
|
|
@@ -3314,7 +3312,7 @@ ${c?`workflows:
|
|
|
3314
3312
|
branches:
|
|
3315
3313
|
only: main
|
|
3316
3314
|
`:""}
|
|
3317
|
-
`}function
|
|
3315
|
+
`}function Jf(e){let{environments:n,awsRegion:r="us-east-1"}=e,i=n.map((a)=>`
|
|
3318
3316
|
deploy-${a.name}:
|
|
3319
3317
|
executor: bun-executor
|
|
3320
3318
|
steps:
|
|
@@ -3390,7 +3388,7 @@ workflows:
|
|
|
3390
3388
|
requires:
|
|
3391
3389
|
- test
|
|
3392
3390
|
${s}
|
|
3393
|
-
`}function
|
|
3391
|
+
`}function Xf(e){let{schedule:n,environment:r,awsRegion:i="us-east-1"}=e;return`version: 2.1
|
|
3394
3392
|
|
|
3395
3393
|
orbs:
|
|
3396
3394
|
aws-cli: circleci/aws-cli@4.0
|
|
@@ -3427,7 +3425,7 @@ workflows:
|
|
|
3427
3425
|
only: main
|
|
3428
3426
|
jobs:
|
|
3429
3427
|
- deploy
|
|
3430
|
-
`}function
|
|
3428
|
+
`}function Qf(e){let{environments:n,awsRegion:r="us-east-1"}=e,i=n.map((a)=>`
|
|
3431
3429
|
deploy-${a}:
|
|
3432
3430
|
executor: bun-executor
|
|
3433
3431
|
steps:
|
|
@@ -3503,7 +3501,7 @@ workflows:
|
|
|
3503
3501
|
requires:
|
|
3504
3502
|
- test
|
|
3505
3503
|
${s}
|
|
3506
|
-
`}function
|
|
3504
|
+
`}function Yf(e){let{regions:n,environment:r}=e,i=n.map((a)=>`
|
|
3507
3505
|
deploy-${a.replace(/-/g,"_")}:
|
|
3508
3506
|
executor: bun-executor
|
|
3509
3507
|
environment:
|
|
@@ -3572,7 +3570,7 @@ workflows:
|
|
|
3572
3570
|
requires:
|
|
3573
3571
|
- test
|
|
3574
3572
|
${s}
|
|
3575
|
-
`}class Ma{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 n=`backup-plan-${Date.now()}-${this.planCounter++}`,r={id:n,...e};return this.backupPlans.set(n,r),r}getBackupPlan(e){return this.backupPlans.get(e)}listBackupPlans(){return Array.from(this.backupPlans.values())}createRDSBackupPlan(e){let{dbInstanceArn:n,schedule:r="0 2 * * *",retentionDays:i=7,vaultName:s="default-vault"}=e;return this.createBackupPlan({name:"RDS Daily Backup",schedule:r,retentionDays:i,vaultName:s,resources:[{resourceArn:n,resourceType:"rds",region:"us-east-1"}],lifecycle:{moveTocoldStorageAfterDays:30,deleteAfterDays:i}})}createDynamoDBBackupPlan(e){let{tableArn:n,schedule:r="0 3 * * *",retentionDays:i=35,crossRegionCopy:s}=e;return this.createBackupPlan({name:"DynamoDB Daily Backup",schedule:r,retentionDays:i,vaultName:"dynamodb-vault",resources:[{resourceArn:n,resourceType:"dynamodb",region:"us-east-1"}],lifecycle:{deleteAfterDays:i},tags:s?{CrossRegionCopy:s.join(",")}:void 0})}createEFSBackupPlan(e){let{fileSystemArn:n,schedule:r="0 1 * * *",retentionDays:i=30}=e;return this.createBackupPlan({name:"EFS Daily Backup",schedule:r,retentionDays:i,vaultName:"efs-vault",resources:[{resourceArn:n,resourceType:"efs",region:"us-east-1"}],lifecycle:{deleteAfterDays:i}})}enableContinuousBackup(e,n=35){let r=`continuous-backup-${Date.now()}-${this.continuousBackupCounter++}`,i={id:r,resourceId:e,enabled:!0,retentionDays:n};return this.continuousBackups.set(r,i),i}getContinuousBackup(e){return this.continuousBackups.get(e)}enablePointInTimeRecovery(e,n){return{enabled:!0,earliestRestorableTime:new Date(Date.now()-604800000),latestRestorableTime:new Date}}async restoreFromBackup(e){let{backupId:n,resourceType:r,targetRegion:i}=e,s={id:`restore-${Date.now()}-${this.restoreCounter++}`,backupId:n,resourceType:r,status:"pending",startTime:new Date,targetRegion:i};return this.restoreJobs.set(s.id,s),setTimeout(()=>{s.status="running"},100),setTimeout(()=>{s.status="completed",s.endTime=new Date},1000),s}async restoreToPointInTime(e){let{sourceResourceArn:n,targetResourceName:r,restoreTime:i,resourceType:s}=e,a={id:`pitr-${Date.now()}-${this.restoreCounter++}`,backupId:`pitr-${i.getTime()}`,resourceType:s,status:"pending",startTime:new Date};return this.restoreJobs.set(a.id,a),console.log(`Restoring ${s} from ${n} to ${r} at ${i.toISOString()}`),setTimeout(()=>{a.status="completed",a.endTime=new Date},2000),a}getRestoreJob(e){return this.restoreJobs.get(e)}listRestoreJobs(){return Array.from(this.restoreJobs.values())}setupCrossRegionReplication(e){let{sourceVault:n,sourceRegion:r,targetRegions:i}=e;console.log("Setting up cross-region replication:"),console.log(` Source: ${n} in ${r}`),console.log(` Targets: ${i.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((n)=>n.resourceArn)}}}}clear(){this.backupPlans.clear(),this.backupVaults.clear(),this.restoreJobs.clear(),this.continuousBackups.clear(),this.planCounter=0,this.restoreCounter=0,this.continuousBackupCounter=0}}var np=new Ma;class Ua{drPlans=new Map;failoverTests=new Map;planCounter=0;testCounter=0;createDRPlan(e){let n=`dr-plan-${Date.now()}-${this.planCounter++}`,r={id:n,...e};return this.drPlans.set(n,r),r}createRDSDRPlan(e){let{primaryDbArn:n,secondaryDbArn:r,primaryRegion:i,secondaryRegion:s,rto:a=60,rpo:c=5}=e;return this.createDRPlan({name:"RDS Multi-Region DR",primaryRegion:i,secondaryRegion:s,rto:a,rpo:c,resources:[{resourceId:"primary-db",resourceType:"rds",primaryArn:n,secondaryArn:r,replicationEnabled:!0}],runbook:this.generateRDSRunbook(i,s),testSchedule:"0 0 1 * *"})}createDynamoDBDRPlan(e){let{tableArn:n,regions:r,rto:i=15,rpo:s=1}=e;return this.createDRPlan({name:"DynamoDB Global Tables DR",primaryRegion:r[0],secondaryRegion:r[1],rto:i,rpo:s,resources:[{resourceId:"dynamodb-table",resourceType:"dynamodb",primaryArn:n,replicationEnabled:!0}],runbook:this.generateDynamoDBRunbook(r)})}generateRDSRunbook(e,n){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 "+n,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,n=!1){let r=this.drPlans.get(e);if(!r)throw Error(`DR plan not found: ${e}`);let i=Date.now(),s=0;console.log(`${n?"[DRY RUN] ":""}Executing failover for plan: ${r.name}`),console.log(`Primary: ${r.primaryRegion} -> Secondary: ${r.secondaryRegion}`),console.log(`RTO: ${r.rto} minutes, RPO: ${r.rpo} minutes`),console.log("");for(let c of r.runbook.steps){if(console.log(`Step ${c.order}: ${c.name}`),console.log(` ${c.description}`),console.log(` Action: ${c.action}`),console.log(` Estimated: ${c.estimatedDuration} minutes`),n)console.log(" [SKIPPED - DRY RUN]");else if(c.automatable)console.log(" [AUTOMATED]");else console.log(" [MANUAL - WAITING]");s++,console.log("")}return{success:!0,duration:(Date.now()-i)/1000/60,completedSteps:s}}scheduleFailoverTest(e,n){let r={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:e,status:"scheduled",startTime:n};return this.failoverTests.set(r.id,r),r}async runFailoverTest(e){let n=this.drPlans.get(e);if(!n)throw Error(`DR plan not found: ${e}`);let r={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:e,status:"running",startTime:new Date,results:[]};this.failoverTests.set(r.id,r),console.log(`Running failover test for plan: ${n.name}`),console.log("This is a non-destructive test using test resources"),console.log("");for(let i of n.runbook.steps){let s=Date.now();console.log(`Testing step ${i.order}: ${i.name}`);let a={step:i.name,status:"success",duration:(Date.now()-s)/1000,message:`Successfully validated step ${i.order}`};r.results.push(a)}return r.status="completed",r.endTime=new Date,r}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 n=[],r=[];if(e.rto<e.rpo)r.push("RTO cannot be less than RPO");if(e.rto>240)n.push("RTO exceeds 4 hours - consider improving recovery time");if(e.rpo>60)n.push("RPO exceeds 1 hour - consider more frequent backups");if(e.resources.length===0)r.push("No resources defined in DR plan");for(let a of e.resources){if(!a.replicationEnabled)n.push(`Resource ${a.resourceId} does not have replication enabled`);if(!a.secondaryArn&&a.resourceType!=="dynamodb")n.push(`Resource ${a.resourceId} does not have secondary resource defined`)}if(e.runbook.steps.length===0)r.push("No recovery steps defined in runbook");let i=e.runbook.steps.reduce((a,c)=>a+c.estimatedDuration,0);if(i>e.rto)n.push(`Estimated recovery duration (${i}m) exceeds RTO (${e.rto}m)`);let s=e.runbook.steps.filter((a)=>!a.automatable);if(s.length>0)n.push(`${s.length} manual steps in runbook - consider automation`);return{valid:r.length===0,warnings:n,errors:r}}clear(){this.drPlans.clear(),this.failoverTests.clear(),this.planCounter=0,this.testCounter=0}}var ip=new Ua;class Ba{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 n=`config-rule-${Date.now()}-${this.ruleCounter++}`,r={id:n,...e};return this.configRules.set(n,r),r}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 n=[];switch(e){case"hipaa":n.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createRdsBackupRule(7),this.createVpcFlowLogsRule());break;case"pci-dss":n.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createIamMfaRule(),this.createRootAccountMfaRule(),this.createVpcFlowLogsRule());break;case"sox":n.push(this.createS3VersioningRule(),this.createCloudTrailEnabledRule(),this.createRdsBackupRule(30),this.createIamPasswordPolicyRule());break;case"gdpr":n.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createRdsSnapshotEncryptionRule());break;case"basic":n.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamMfaRule(),this.createRootAccountMfaRule());break}return n}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 n={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)n.Properties.Source.SourceIdentifier=e.identifier;if(e.source==="CUSTOM_LAMBDA"&&e.lambdaFunctionArn)n.Properties.Source.SourceIdentifier=e.lambdaFunctionArn,n.Properties.Source.SourceDetails=[{EventSource:"aws.config",MessageType:"ConfigurationItemChangeNotification"}];if(e.inputParameters)n.Properties.InputParameters=JSON.stringify(e.inputParameters);if(e.scope){if(n.Properties.Scope={},e.scope.complianceResourceTypes)n.Properties.Scope.ComplianceResourceTypes=e.scope.complianceResourceTypes;if(e.scope.tagKey)n.Properties.Scope.TagKey=e.scope.tagKey;if(e.scope.tagValue)n.Properties.Scope.TagValue=e.scope.tagValue}if(e.maxExecutionFrequency)n.Properties.MaximumExecutionFrequency=e.maxExecutionFrequency;return n}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 op=new Ba;class Fa{trails=new Map;trailCounter=0;createTrail(e){let n=`trail-${Date.now()}-${this.trailCounter++}`,r={id:n,...e};return this.trails.set(n,r),r}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 n=[];if(e.s3DataBuckets&&e.s3DataBuckets.length>0)n.push({type:"AWS::S3::Object",values:e.s3DataBuckets.map((r)=>`arn:aws:s3:::${r}/*`)});if(e.lambdaFunctions&&e.lambdaFunctions.length>0)n.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:n}]})}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 n={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)n.Properties.S3KeyPrefix=e.s3KeyPrefix;if(e.cloudWatchLogsLogGroupArn)n.Properties.CloudWatchLogsLogGroupArn=e.cloudWatchLogsLogGroupArn;if(e.cloudWatchLogsRoleArn)n.Properties.CloudWatchLogsRoleArn=e.cloudWatchLogsRoleArn;if(e.snsTopicName)n.Properties.SnsTopicName=e.snsTopicName;if(e.kmsKeyId)n.Properties.KMSKeyId=e.kmsKeyId;if(e.eventSelectors)n.Properties.EventSelectors=e.eventSelectors.map((r)=>({ReadWriteType:r.readWriteType,IncludeManagementEvents:r.includeManagementEvents??!0,...r.dataResources&&{DataResources:r.dataResources.map((i)=>({Type:i.type,Values:i.values}))},...r.excludeManagementEventSources&&{ExcludeManagementEventSources:r.excludeManagementEventSources}}));if(e.insightSelectors)n.Properties.InsightSelectors=e.insightSelectors.map((r)=>({InsightType:r.insightType}));if(e.advancedEventSelectors)n.Properties.AdvancedEventSelectors=e.advancedEventSelectors.map((r)=>({Name:r.name,FieldSelectors:r.fieldSelectors.map((i)=>({Field:i.field,...i.equals&&{Equals:i.equals},...i.startsWith&&{StartsWith:i.startsWith},...i.endsWith&&{EndsWith:i.endsWith},...i.notEquals&&{NotEquals:i.notEquals},...i.notStartsWith&&{NotStartsWith:i.notStartsWith},...i.notEndsWith&&{NotEndsWith:i.notEndsWith}}))}));return n}generateBucketPolicy(e,n){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:n.map((r)=>`arn:aws:s3:::${e}/AWSLogs/${r}/*`),Condition:{StringEquals:{"s3:x-amz-acl":"bucket-owner-full-control"}}}]}}clear(){this.trails.clear(),this.trailCounter=0}}var sp=new Fa;class ja{detectors=new Map;threatIntelSets=new Map;ipSets=new Map;filters=new Map;detectorCounter=0;threatIntelCounter=0;ipSetCounter=0;filterCounter=0;createDetector(e){let n=`detector-${Date.now()}-${this.detectorCounter++}`,r={id:n,...e};return this.detectors.set(n,r),r}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 n=`threat-intel-${Date.now()}-${this.threatIntelCounter++}`,r={id:n,...e};return this.threatIntelSets.set(n,r),r}createIPSet(e){let n=`ip-set-${Date.now()}-${this.ipSetCounter++}`,r={id:n,...e};return this.ipSets.set(n,r),r}createFindingFilter(e){let n=`filter-${Date.now()}-${this.filterCounter++}`,r={id:n,...e};return this.filters.set(n,r),r}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,n,r){return this.createFindingFilter({detectorId:e,name:`filter-finding-types-${r.toLowerCase()}`,description:`${r==="ARCHIVE"?"Archive":"Keep"} specific finding types`,action:r,rank:2,findingCriteria:{criterion:{type:{eq:n}}}})}createTrustedIPFilter(e,n){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:n}}}})}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 n={Type:"AWS::GuardDuty::Detector",Properties:{Enable:e.enable}};if(e.findingPublishingFrequency)n.Properties.FindingPublishingFrequency=e.findingPublishingFrequency;if(e.dataSources){if(n.Properties.DataSources={},e.dataSources.s3Logs)n.Properties.DataSources.S3Logs={Enable:e.dataSources.s3Logs.enable};if(e.dataSources.kubernetes)n.Properties.DataSources.Kubernetes={AuditLogs:{Enable:e.dataSources.kubernetes.auditLogs.enable}};if(e.dataSources.malwareProtection)n.Properties.DataSources.MalwareProtection={ScanEc2InstanceWithFindings:{EbsVolumes:{Enable:e.dataSources.malwareProtection.scanEc2InstanceWithFindings.ebsVolumes.enable}}}}if(e.features)n.Properties.Features=e.features.map((r)=>({Name:r.name,Status:r.status,...r.additionalConfiguration&&{AdditionalConfiguration:r.additionalConfiguration}}));return n}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 ap=new ja;class zr{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 n=`hub-${Date.now()}-${this.hubCounter++}`,r={id:n,...e};return this.hubs.set(n,r),r}createComprehensiveHub(){return this.createHub({enable:!0,controlFindingGenerator:"SECURITY_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...zr.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...zr.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...zr.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...zr.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((n)=>({value:n,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,n){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:n.map((r)=>({value:r,comparison:"PREFIX"}))},ruleStatus:"ENABLED",ruleOrder:10}}getHub(e){return this.hubs.get(e)}listHubs(){return Array.from(this.hubs.values())}generateHubCF(e){let n={Type:"AWS::SecurityHub::Hub",Properties:{}};if(e.controlFindingGenerator)n.Properties.ControlFindingGenerator=e.controlFindingGenerator;if(e.enableDefaultStandards!==void 0)n.Properties.EnableDefaultStandards=e.enableDefaultStandards;return n}generateStandardCF(e){let n={Type:"AWS::SecurityHub::Standard",Properties:{StandardsArn:e.arn}};if(e.disabledControls&&e.disabledControls.length>0)n.Properties.DisabledStandardsControls=e.disabledControls.map((r)=>({StandardsControlArn:r,Reason:"Disabled by configuration"}));return n}generateAutomationRuleCF(e){return{Type:"AWS::SecurityHub::AutomationRule",Properties:{RuleName:e.ruleName,Description:e.description,Actions:e.actions.map((n)=>({Type:n.type,FindingFieldsUpdate:n.findingFieldsUpdate})),Criteria:e.criteria,RuleStatus:e.ruleStatus,RuleOrder:e.ruleOrder}}}clear(){this.hubs.clear(),this.hubCounter=0,this.ruleCounter=0}}var cp=new zr;class Va{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;createDeployment(e){let n=`bg-deployment-${Date.now()}-${this.deploymentCounter++}`,r={id:n,...e};return this.deployments.set(n,r),r}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,n=!1){let r=this.deployments.get(e);if(!r)throw Error(`Deployment not found: ${e}`);let i={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!1,errors:[]};console.log(`${n?"[DRY RUN] ":""}Starting blue/green deployment: ${r.name}`),console.log(` Active environment: ${r.activeEnvironment}`),console.log(` Routing type: ${r.routingConfig.type}`);let s=r.activeEnvironment==="blue"?"green":"blue";if(console.log(` Switching to: ${s}`),console.log(`\\n1. Deploying to ${s} environment`),!n)await new Promise((a)=>setTimeout(a,100));if(console.log(`\\n2. Running health checks on ${s} environment`),r.healthCheckConfig){let a=await this.runHealthChecks(r,s,n);if(i.healthChecksPassed=a,!a){if(i.errors?.push("Health checks failed"),i.endTime=new Date,r.autoRollback)console.log(" Auto-rollback enabled - keeping current environment active"),i.rolledBackAt=new Date;return this.recordDeployment(e,i),i}}else i.healthChecksPassed=!0;if(console.log(`\\n3. Switching traffic to ${s} environment`),!n)r.activeEnvironment=s,i.switchedAt=new Date;if(console.log(`\\n4. Monitoring ${s} environment`),!n)await new Promise((a)=>setTimeout(a,100));return i.success=!0,i.endTime=new Date,console.log("\\n✓ Deployment completed successfully"),this.recordDeployment(e,i),i}async rollback(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!0,errors:[]};console.log(`Rolling back deployment: ${n.name}`);let i=n.activeEnvironment==="blue"?"green":"blue";return n.activeEnvironment=i,r.success=!0,r.rolledBackAt=new Date,r.endTime=new Date,console.log(` Switched back to: ${i}`),this.recordDeployment(e,r),r}async runHealthChecks(e,n,r){let i=e.healthCheckConfig;if(console.log(` Health check path: ${i.path||"/"}`),console.log(` Healthy threshold: ${i.healthyThreshold}`),console.log(` Interval: ${i.interval}s`),r)return console.log(" [SKIPPED - DRY RUN]"),!0;let s=0,a=i.healthyThreshold+2;for(let c=0;c<a;c++)if(await new Promise((d)=>setTimeout(d,50)),Math.random()>0.1){if(s++,console.log(` Check ${c+1}: ✓ Healthy (${s}/${i.healthyThreshold})`),s>=i.healthyThreshold)return!0}else s=0,console.log(` Check ${c+1}: ✗ Unhealthy`);return!1}recordDeployment(e,n){if(!this.deploymentHistory.has(e))this.deploymentHistory.set(e,[]);this.deploymentHistory.get(e).push(n)}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(e){return this.deploymentHistory.get(e)||[]}generateALBListenerCF(e){let n=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:n.targetGroupArn}]}}}generateRoute53RecordSetCF(e,n){return[{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.routingConfig.hostedZoneId,Name:n,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:n,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 lp=new Va;class Ki{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 n=`canary-${Date.now()}-${this.deploymentCounter++}`,r={id:n,...e};return this.deployments.set(n,r),r}createLambdaCanaryDeployment(e){let n=e.strategy||"BALANCED",r=Ki.Strategies[n].map((i)=>({...i,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:r,currentStage:0,status:"pending",autoPromote:e.autoPromote??!0,autoRollback:!0})}createECSCanaryDeployment(e){let n=e.strategy||"CONSERVATIVE",r=Ki.Strategies[n];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:r,currentStage:0,status:"pending",autoRollback:!0})}async executeDeployment(e,n=!1){let r=this.deployments.get(e);if(!r)throw Error(`Deployment not found: ${e}`);let i={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,completedStages:0,rolledBack:!1};console.log(`${n?"[DRY RUN] ":""}Starting canary deployment: ${r.name}`),console.log(` Strategy: ${r.stages.length} stages`),console.log(` Auto-promote: ${r.autoPromote}`),console.log(` Auto-rollback: ${r.autoRollback}`),console.log(""),r.status="in_progress";for(let s=0;s<r.stages.length;s++){let a=r.stages[s];if(r.currentStage=s,console.log(`Stage ${s+1}/${r.stages.length}: ${a.name}`),console.log(` Traffic: ${a.trafficPercentage}% canary, ${100-a.trafficPercentage}% baseline`),console.log(` Duration: ${a.durationMinutes} minutes`),!n)r.baselineVersion.weight=100-a.trafficPercentage,r.canaryVersion.weight=a.trafficPercentage;if(!await this.monitorStage(r,a,n)){if(console.log(" ✗ Stage failed - metrics exceeded thresholds"),r.autoRollback)console.log("\\n Rolling back deployment..."),await this.rollback(e,n),i.rolledBack=!0,i.reason="Metrics exceeded thresholds";return i.endTime=new Date,r.status="rolled_back",this.recordDeployment(e,i),i}console.log(" ✓ Stage completed successfully"),i.completedStages++,console.log("")}return r.status="completed",i.success=!0,i.endTime=new Date,console.log("✓ Canary deployment completed successfully"),this.recordDeployment(e,i),i}async monitorStage(e,n,r){if(console.log(" Monitoring metrics..."),r)return console.log(" [SKIPPED - DRY RUN]"),!0;await new Promise((s)=>setTimeout(s,100));let i={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)*n.trafficPercentage/100)};if(e.metrics=i,console.log(` Baseline: ${i.baselineErrorRate.toFixed(2)}% errors, ${i.baselineLatencyP99.toFixed(0)}ms P99`),console.log(` Canary: ${i.canaryErrorRate.toFixed(2)}% errors, ${i.canaryLatencyP99.toFixed(0)}ms P99`),n.alarmThresholds){let{errorRate:s,latencyP99:a}=n.alarmThresholds;if(s&&i.canaryErrorRate>s)return console.log(` ⚠ Error rate exceeded threshold: ${i.canaryErrorRate.toFixed(2)}% > ${s}%`),!1;if(a&&i.canaryLatencyP99>a)return console.log(` ⚠ Latency P99 exceeded threshold: ${i.canaryLatencyP99.toFixed(0)}ms > ${a}ms`),!1}return!0}async rollback(e,n=!1){let r=this.deployments.get(e);if(!r)throw Error(`Deployment not found: ${e}`);if(console.log(`${n?"[DRY RUN] ":""}Rolling back canary deployment: ${r.name}`),!n)r.baselineVersion.weight=100,r.canaryVersion.weight=0,r.status="rolled_back";console.log(" Traffic restored to baseline: 100%")}promoteCanary(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);console.log(`Promoting canary to baseline: ${n.name}`);let r=n.baselineVersion;n.baselineVersion=n.canaryVersion,n.canaryVersion=r,n.baselineVersion.weight=100,n.canaryVersion.weight=0,n.status="completed",console.log(" Canary promoted successfully")}recordDeployment(e,n){if(!this.deploymentHistory.has(e))this.deploymentHistory.set(e,[]);this.deploymentHistory.get(e).push(n)}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(e){return this.deploymentHistory.get(e)||[]}generateLambdaAliasCF(e,n){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:{Ref:"LambdaFunction"},Name:n,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 dp=new Ki;class za{tests=new Map;testCounter=0;createTest(e){let n=`abtest-${Date.now()}-${this.testCounter++}`,r={id:n,...e};return this.tests.set(n,r),r}createSimpleABTest(e){let n=e.variantTrafficPercentage||50;return this.createTest({name:e.name,description:e.description,variants:[{id:"control",name:"Control",description:"Original version",trafficPercentage:100-n,targetGroupArn:e.controlTargetGroupArn,weight:100-n},{id:"variant-a",name:"Variant A",description:"Test version",trafficPercentage:n,targetGroupArn:e.variantTargetGroupArn,weight:n}],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 n=e.variants.reduce((r,i)=>r+i.trafficPercentage,0);if(n!==100)throw Error(`Traffic percentages must sum to 100, got ${n}`);return this.createTest({name:e.name,description:e.description,variants:e.variants.map((r,i)=>({id:`variant-${i}`,name:r.name,description:r.description,trafficPercentage:r.trafficPercentage,targetGroupArn:r.targetGroupArn,weight:r.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 n=this.tests.get(e);if(!n)throw Error(`Test not found: ${e}`);if(n.status!=="draft"&&n.status!=="paused")throw Error(`Cannot start test in ${n.status} status`);n.status="active",n.startTime=new Date,console.log(`Started A/B test: ${n.name}`),console.log(` Variants: ${n.variants.length}`),n.variants.forEach((r)=>{console.log(` - ${r.name}: ${r.trafficPercentage}%`)})}pauseTest(e){let n=this.tests.get(e);if(!n)throw Error(`Test not found: ${e}`);n.status="paused",console.log(`Paused A/B test: ${n.name}`)}updateTrafficSplit(e,n,r){let i=this.tests.get(e);if(!i)throw Error(`Test not found: ${e}`);let s=i.variants.find((c)=>c.id===n);if(!s)throw Error(`Variant not found: ${n}`);let a=s.trafficPercentage;s.trafficPercentage=r,s.weight=r,console.log(`Updated ${s.name} traffic: ${a}% → ${r}%`)}analyzeResults(e){let n=this.tests.get(e);if(!n)throw Error(`Test not found: ${e}`);if(!n.metrics)n.metrics=this.collectMetrics(n);let r=n.variants[0],i=0;for(let m of n.variants){let p=n.metrics.variants[m.id];if(p&&p.conversionRate>i)i=p.conversionRate,r=m}let s=n.metrics.variants.control||n.metrics.variants[n.variants[0].id],a=n.metrics.variants[r.id],c=(a.conversionRate-s.conversionRate)/s.conversionRate*100,u=100,d=a.requests>u&&s.requests>u&&Math.abs(c)>10;return{testId:e,winningVariant:r.name,confidence:d?95:75,improvement:c,statisticalSignificance:d,metrics:n.metrics,recommendation:this.generateRecommendation(c,d,r.name)}}declareWinner(e,n){let r=this.tests.get(e);if(!r)throw Error(`Test not found: ${e}`);let i=r.variants.find((s)=>s.id===n);if(!i)throw Error(`Variant not found: ${n}`);r.variants.forEach((s)=>{if(s.id===n)s.trafficPercentage=100,s.weight=100;else s.trafficPercentage=0,s.weight=0}),r.status="completed",r.endTime=new Date,r.winner=n,console.log(`Declared winner: ${i.name}`),console.log(` All traffic now routed to ${i.name}`)}collectMetrics(e){let n={},r=0;for(let i of e.variants){let s=Math.floor(Math.random()*1000)+500,a=Math.floor(s*(Math.random()*0.1+0.05)),c=a/s*100;n[i.id]={requests:s,conversions:a,conversionRate:c,averageLatency:150+Math.random()*100,errorRate:Math.random()*0.5,revenue:a*(Math.random()*50+100)},r+=s}return{variants:n,totalRequests:r,startTime:e.startTime,lastUpdated:new Date}}generateRecommendation(e,n,r){if(!n)return"Continue test - sample size too small or no significant difference detected";if(e>20)return`Strong winner detected - ${r} shows ${e.toFixed(1)}% improvement. Recommend deploying to all traffic.`;if(e>10)return`Moderate improvement - ${r} shows ${e.toFixed(1)}% improvement. Consider deploying.`;if(e>0)return`Minor improvement - ${r} 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((n)=>({TargetGroupArn:n.targetGroupArn,Weight:n.weight})),TargetGroupStickinessConfig:{Enabled:e.routingStrategy.stickySession||!1,DurationSeconds:e.routingStrategy.sessionDuration?e.routingStrategy.sessionDuration*60:void 0}}}]}}}generateLambdaEdgeFunction(e){return`'use strict';
|
|
3573
|
+
`}class Ga{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 n=`backup-plan-${Date.now()}-${this.planCounter++}`,r={id:n,...e};return this.backupPlans.set(n,r),r}getBackupPlan(e){return this.backupPlans.get(e)}listBackupPlans(){return Array.from(this.backupPlans.values())}createRDSBackupPlan(e){let{dbInstanceArn:n,schedule:r="0 2 * * *",retentionDays:i=7,vaultName:s="default-vault"}=e;return this.createBackupPlan({name:"RDS Daily Backup",schedule:r,retentionDays:i,vaultName:s,resources:[{resourceArn:n,resourceType:"rds",region:"us-east-1"}],lifecycle:{moveTocoldStorageAfterDays:30,deleteAfterDays:i}})}createDynamoDBBackupPlan(e){let{tableArn:n,schedule:r="0 3 * * *",retentionDays:i=35,crossRegionCopy:s}=e;return this.createBackupPlan({name:"DynamoDB Daily Backup",schedule:r,retentionDays:i,vaultName:"dynamodb-vault",resources:[{resourceArn:n,resourceType:"dynamodb",region:"us-east-1"}],lifecycle:{deleteAfterDays:i},tags:s?{CrossRegionCopy:s.join(",")}:void 0})}createEFSBackupPlan(e){let{fileSystemArn:n,schedule:r="0 1 * * *",retentionDays:i=30}=e;return this.createBackupPlan({name:"EFS Daily Backup",schedule:r,retentionDays:i,vaultName:"efs-vault",resources:[{resourceArn:n,resourceType:"efs",region:"us-east-1"}],lifecycle:{deleteAfterDays:i}})}enableContinuousBackup(e,n=35){let r=`continuous-backup-${Date.now()}-${this.continuousBackupCounter++}`,i={id:r,resourceId:e,enabled:!0,retentionDays:n};return this.continuousBackups.set(r,i),i}getContinuousBackup(e){return this.continuousBackups.get(e)}enablePointInTimeRecovery(e,n){return{enabled:!0,earliestRestorableTime:new Date(Date.now()-604800000),latestRestorableTime:new Date}}async restoreFromBackup(e){let{backupId:n,resourceType:r,targetRegion:i}=e,s={id:`restore-${Date.now()}-${this.restoreCounter++}`,backupId:n,resourceType:r,status:"pending",startTime:new Date,targetRegion:i};return this.restoreJobs.set(s.id,s),setTimeout(()=>{s.status="running"},100),setTimeout(()=>{s.status="completed",s.endTime=new Date},1000),s}async restoreToPointInTime(e){let{sourceResourceArn:n,targetResourceName:r,restoreTime:i,resourceType:s}=e,a={id:`pitr-${Date.now()}-${this.restoreCounter++}`,backupId:`pitr-${i.getTime()}`,resourceType:s,status:"pending",startTime:new Date};return this.restoreJobs.set(a.id,a),console.log(`Restoring ${s} from ${n} to ${r} at ${i.toISOString()}`),setTimeout(()=>{a.status="completed",a.endTime=new Date},2000),a}getRestoreJob(e){return this.restoreJobs.get(e)}listRestoreJobs(){return Array.from(this.restoreJobs.values())}setupCrossRegionReplication(e){let{sourceVault:n,sourceRegion:r,targetRegions:i}=e;console.log("Setting up cross-region replication:"),console.log(` Source: ${n} in ${r}`),console.log(` Targets: ${i.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((n)=>n.resourceArn)}}}}clear(){this.backupPlans.clear(),this.backupVaults.clear(),this.restoreJobs.clear(),this.continuousBackups.clear(),this.planCounter=0,this.restoreCounter=0,this.continuousBackupCounter=0}}var fp=new Ga;class qa{drPlans=new Map;failoverTests=new Map;planCounter=0;testCounter=0;createDRPlan(e){let n=`dr-plan-${Date.now()}-${this.planCounter++}`,r={id:n,...e};return this.drPlans.set(n,r),r}createRDSDRPlan(e){let{primaryDbArn:n,secondaryDbArn:r,primaryRegion:i,secondaryRegion:s,rto:a=60,rpo:c=5}=e;return this.createDRPlan({name:"RDS Multi-Region DR",primaryRegion:i,secondaryRegion:s,rto:a,rpo:c,resources:[{resourceId:"primary-db",resourceType:"rds",primaryArn:n,secondaryArn:r,replicationEnabled:!0}],runbook:this.generateRDSRunbook(i,s),testSchedule:"0 0 1 * *"})}createDynamoDBDRPlan(e){let{tableArn:n,regions:r,rto:i=15,rpo:s=1}=e;return this.createDRPlan({name:"DynamoDB Global Tables DR",primaryRegion:r[0],secondaryRegion:r[1],rto:i,rpo:s,resources:[{resourceId:"dynamodb-table",resourceType:"dynamodb",primaryArn:n,replicationEnabled:!0}],runbook:this.generateDynamoDBRunbook(r)})}generateRDSRunbook(e,n){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 "+n,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,n=!1){let r=this.drPlans.get(e);if(!r)throw Error(`DR plan not found: ${e}`);let i=Date.now(),s=0;console.log(`${n?"[DRY RUN] ":""}Executing failover for plan: ${r.name}`),console.log(`Primary: ${r.primaryRegion} -> Secondary: ${r.secondaryRegion}`),console.log(`RTO: ${r.rto} minutes, RPO: ${r.rpo} minutes`),console.log("");for(let c of r.runbook.steps){if(console.log(`Step ${c.order}: ${c.name}`),console.log(` ${c.description}`),console.log(` Action: ${c.action}`),console.log(` Estimated: ${c.estimatedDuration} minutes`),n)console.log(" [SKIPPED - DRY RUN]");else if(c.automatable)console.log(" [AUTOMATED]");else console.log(" [MANUAL - WAITING]");s++,console.log("")}return{success:!0,duration:(Date.now()-i)/1000/60,completedSteps:s}}scheduleFailoverTest(e,n){let r={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:e,status:"scheduled",startTime:n};return this.failoverTests.set(r.id,r),r}async runFailoverTest(e){let n=this.drPlans.get(e);if(!n)throw Error(`DR plan not found: ${e}`);let r={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:e,status:"running",startTime:new Date,results:[]};this.failoverTests.set(r.id,r),console.log(`Running failover test for plan: ${n.name}`),console.log("This is a non-destructive test using test resources"),console.log("");for(let i of n.runbook.steps){let s=Date.now();console.log(`Testing step ${i.order}: ${i.name}`);let a={step:i.name,status:"success",duration:(Date.now()-s)/1000,message:`Successfully validated step ${i.order}`};r.results.push(a)}return r.status="completed",r.endTime=new Date,r}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 n=[],r=[];if(e.rto<e.rpo)r.push("RTO cannot be less than RPO");if(e.rto>240)n.push("RTO exceeds 4 hours - consider improving recovery time");if(e.rpo>60)n.push("RPO exceeds 1 hour - consider more frequent backups");if(e.resources.length===0)r.push("No resources defined in DR plan");for(let a of e.resources){if(!a.replicationEnabled)n.push(`Resource ${a.resourceId} does not have replication enabled`);if(!a.secondaryArn&&a.resourceType!=="dynamodb")n.push(`Resource ${a.resourceId} does not have secondary resource defined`)}if(e.runbook.steps.length===0)r.push("No recovery steps defined in runbook");let i=e.runbook.steps.reduce((a,c)=>a+c.estimatedDuration,0);if(i>e.rto)n.push(`Estimated recovery duration (${i}m) exceeds RTO (${e.rto}m)`);let s=e.runbook.steps.filter((a)=>!a.automatable);if(s.length>0)n.push(`${s.length} manual steps in runbook - consider automation`);return{valid:r.length===0,warnings:n,errors:r}}clear(){this.drPlans.clear(),this.failoverTests.clear(),this.planCounter=0,this.testCounter=0}}var hp=new qa;class Wa{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 n=`config-rule-${Date.now()}-${this.ruleCounter++}`,r={id:n,...e};return this.configRules.set(n,r),r}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 n=[];switch(e){case"hipaa":n.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createRdsBackupRule(7),this.createVpcFlowLogsRule());break;case"pci-dss":n.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createIamMfaRule(),this.createRootAccountMfaRule(),this.createVpcFlowLogsRule());break;case"sox":n.push(this.createS3VersioningRule(),this.createCloudTrailEnabledRule(),this.createRdsBackupRule(30),this.createIamPasswordPolicyRule());break;case"gdpr":n.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createRdsSnapshotEncryptionRule());break;case"basic":n.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamMfaRule(),this.createRootAccountMfaRule());break}return n}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 n={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)n.Properties.Source.SourceIdentifier=e.identifier;if(e.source==="CUSTOM_LAMBDA"&&e.lambdaFunctionArn)n.Properties.Source.SourceIdentifier=e.lambdaFunctionArn,n.Properties.Source.SourceDetails=[{EventSource:"aws.config",MessageType:"ConfigurationItemChangeNotification"}];if(e.inputParameters)n.Properties.InputParameters=JSON.stringify(e.inputParameters);if(e.scope){if(n.Properties.Scope={},e.scope.complianceResourceTypes)n.Properties.Scope.ComplianceResourceTypes=e.scope.complianceResourceTypes;if(e.scope.tagKey)n.Properties.Scope.TagKey=e.scope.tagKey;if(e.scope.tagValue)n.Properties.Scope.TagValue=e.scope.tagValue}if(e.maxExecutionFrequency)n.Properties.MaximumExecutionFrequency=e.maxExecutionFrequency;return n}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 yp=new Wa;class Ka{trails=new Map;trailCounter=0;createTrail(e){let n=`trail-${Date.now()}-${this.trailCounter++}`,r={id:n,...e};return this.trails.set(n,r),r}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 n=[];if(e.s3DataBuckets&&e.s3DataBuckets.length>0)n.push({type:"AWS::S3::Object",values:e.s3DataBuckets.map((r)=>`arn:aws:s3:::${r}/*`)});if(e.lambdaFunctions&&e.lambdaFunctions.length>0)n.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:n}]})}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 n={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)n.Properties.S3KeyPrefix=e.s3KeyPrefix;if(e.cloudWatchLogsLogGroupArn)n.Properties.CloudWatchLogsLogGroupArn=e.cloudWatchLogsLogGroupArn;if(e.cloudWatchLogsRoleArn)n.Properties.CloudWatchLogsRoleArn=e.cloudWatchLogsRoleArn;if(e.snsTopicName)n.Properties.SnsTopicName=e.snsTopicName;if(e.kmsKeyId)n.Properties.KMSKeyId=e.kmsKeyId;if(e.eventSelectors)n.Properties.EventSelectors=e.eventSelectors.map((r)=>({ReadWriteType:r.readWriteType,IncludeManagementEvents:r.includeManagementEvents??!0,...r.dataResources&&{DataResources:r.dataResources.map((i)=>({Type:i.type,Values:i.values}))},...r.excludeManagementEventSources&&{ExcludeManagementEventSources:r.excludeManagementEventSources}}));if(e.insightSelectors)n.Properties.InsightSelectors=e.insightSelectors.map((r)=>({InsightType:r.insightType}));if(e.advancedEventSelectors)n.Properties.AdvancedEventSelectors=e.advancedEventSelectors.map((r)=>({Name:r.name,FieldSelectors:r.fieldSelectors.map((i)=>({Field:i.field,...i.equals&&{Equals:i.equals},...i.startsWith&&{StartsWith:i.startsWith},...i.endsWith&&{EndsWith:i.endsWith},...i.notEquals&&{NotEquals:i.notEquals},...i.notStartsWith&&{NotStartsWith:i.notStartsWith},...i.notEndsWith&&{NotEndsWith:i.notEndsWith}}))}));return n}generateBucketPolicy(e,n){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:n.map((r)=>`arn:aws:s3:::${e}/AWSLogs/${r}/*`),Condition:{StringEquals:{"s3:x-amz-acl":"bucket-owner-full-control"}}}]}}clear(){this.trails.clear(),this.trailCounter=0}}var bp=new Ka;class Ja{detectors=new Map;threatIntelSets=new Map;ipSets=new Map;filters=new Map;detectorCounter=0;threatIntelCounter=0;ipSetCounter=0;filterCounter=0;createDetector(e){let n=`detector-${Date.now()}-${this.detectorCounter++}`,r={id:n,...e};return this.detectors.set(n,r),r}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 n=`threat-intel-${Date.now()}-${this.threatIntelCounter++}`,r={id:n,...e};return this.threatIntelSets.set(n,r),r}createIPSet(e){let n=`ip-set-${Date.now()}-${this.ipSetCounter++}`,r={id:n,...e};return this.ipSets.set(n,r),r}createFindingFilter(e){let n=`filter-${Date.now()}-${this.filterCounter++}`,r={id:n,...e};return this.filters.set(n,r),r}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,n,r){return this.createFindingFilter({detectorId:e,name:`filter-finding-types-${r.toLowerCase()}`,description:`${r==="ARCHIVE"?"Archive":"Keep"} specific finding types`,action:r,rank:2,findingCriteria:{criterion:{type:{eq:n}}}})}createTrustedIPFilter(e,n){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:n}}}})}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 n={Type:"AWS::GuardDuty::Detector",Properties:{Enable:e.enable}};if(e.findingPublishingFrequency)n.Properties.FindingPublishingFrequency=e.findingPublishingFrequency;if(e.dataSources){if(n.Properties.DataSources={},e.dataSources.s3Logs)n.Properties.DataSources.S3Logs={Enable:e.dataSources.s3Logs.enable};if(e.dataSources.kubernetes)n.Properties.DataSources.Kubernetes={AuditLogs:{Enable:e.dataSources.kubernetes.auditLogs.enable}};if(e.dataSources.malwareProtection)n.Properties.DataSources.MalwareProtection={ScanEc2InstanceWithFindings:{EbsVolumes:{Enable:e.dataSources.malwareProtection.scanEc2InstanceWithFindings.ebsVolumes.enable}}}}if(e.features)n.Properties.Features=e.features.map((r)=>({Name:r.name,Status:r.status,...r.additionalConfiguration&&{AdditionalConfiguration:r.additionalConfiguration}}));return n}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 Sp=new Ja;class Gr{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 n=`hub-${Date.now()}-${this.hubCounter++}`,r={id:n,...e};return this.hubs.set(n,r),r}createComprehensiveHub(){return this.createHub({enable:!0,controlFindingGenerator:"SECURITY_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...Gr.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...Gr.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...Gr.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...Gr.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((n)=>({value:n,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,n){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:n.map((r)=>({value:r,comparison:"PREFIX"}))},ruleStatus:"ENABLED",ruleOrder:10}}getHub(e){return this.hubs.get(e)}listHubs(){return Array.from(this.hubs.values())}generateHubCF(e){let n={Type:"AWS::SecurityHub::Hub",Properties:{}};if(e.controlFindingGenerator)n.Properties.ControlFindingGenerator=e.controlFindingGenerator;if(e.enableDefaultStandards!==void 0)n.Properties.EnableDefaultStandards=e.enableDefaultStandards;return n}generateStandardCF(e){let n={Type:"AWS::SecurityHub::Standard",Properties:{StandardsArn:e.arn}};if(e.disabledControls&&e.disabledControls.length>0)n.Properties.DisabledStandardsControls=e.disabledControls.map((r)=>({StandardsControlArn:r,Reason:"Disabled by configuration"}));return n}generateAutomationRuleCF(e){return{Type:"AWS::SecurityHub::AutomationRule",Properties:{RuleName:e.ruleName,Description:e.description,Actions:e.actions.map((n)=>({Type:n.type,FindingFieldsUpdate:n.findingFieldsUpdate})),Criteria:e.criteria,RuleStatus:e.ruleStatus,RuleOrder:e.ruleOrder}}}clear(){this.hubs.clear(),this.hubCounter=0,this.ruleCounter=0}}var vp=new Gr;class Xa{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;createDeployment(e){let n=`bg-deployment-${Date.now()}-${this.deploymentCounter++}`,r={id:n,...e};return this.deployments.set(n,r),r}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,n=!1){let r=this.deployments.get(e);if(!r)throw Error(`Deployment not found: ${e}`);let i={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!1,errors:[]};console.log(`${n?"[DRY RUN] ":""}Starting blue/green deployment: ${r.name}`),console.log(` Active environment: ${r.activeEnvironment}`),console.log(` Routing type: ${r.routingConfig.type}`);let s=r.activeEnvironment==="blue"?"green":"blue";if(console.log(` Switching to: ${s}`),console.log(`\\n1. Deploying to ${s} environment`),!n)await new Promise((a)=>setTimeout(a,100));if(console.log(`\\n2. Running health checks on ${s} environment`),r.healthCheckConfig){let a=await this.runHealthChecks(r,s,n);if(i.healthChecksPassed=a,!a){if(i.errors?.push("Health checks failed"),i.endTime=new Date,r.autoRollback)console.log(" Auto-rollback enabled - keeping current environment active"),i.rolledBackAt=new Date;return this.recordDeployment(e,i),i}}else i.healthChecksPassed=!0;if(console.log(`\\n3. Switching traffic to ${s} environment`),!n)r.activeEnvironment=s,i.switchedAt=new Date;if(console.log(`\\n4. Monitoring ${s} environment`),!n)await new Promise((a)=>setTimeout(a,100));return i.success=!0,i.endTime=new Date,console.log("\\n✓ Deployment completed successfully"),this.recordDeployment(e,i),i}async rollback(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!0,errors:[]};console.log(`Rolling back deployment: ${n.name}`);let i=n.activeEnvironment==="blue"?"green":"blue";return n.activeEnvironment=i,r.success=!0,r.rolledBackAt=new Date,r.endTime=new Date,console.log(` Switched back to: ${i}`),this.recordDeployment(e,r),r}async runHealthChecks(e,n,r){let i=e.healthCheckConfig;if(console.log(` Health check path: ${i.path||"/"}`),console.log(` Healthy threshold: ${i.healthyThreshold}`),console.log(` Interval: ${i.interval}s`),r)return console.log(" [SKIPPED - DRY RUN]"),!0;let s=0,a=i.healthyThreshold+2;for(let c=0;c<a;c++)if(await new Promise((d)=>setTimeout(d,50)),Math.random()>0.1){if(s++,console.log(` Check ${c+1}: ✓ Healthy (${s}/${i.healthyThreshold})`),s>=i.healthyThreshold)return!0}else s=0,console.log(` Check ${c+1}: ✗ Unhealthy`);return!1}recordDeployment(e,n){if(!this.deploymentHistory.has(e))this.deploymentHistory.set(e,[]);this.deploymentHistory.get(e).push(n)}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(e){return this.deploymentHistory.get(e)||[]}generateALBListenerCF(e){let n=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:n.targetGroupArn}]}}}generateRoute53RecordSetCF(e,n){return[{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:e.routingConfig.hostedZoneId,Name:n,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:n,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 Cp=new Xa;class Zi{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 n=`canary-${Date.now()}-${this.deploymentCounter++}`,r={id:n,...e};return this.deployments.set(n,r),r}createLambdaCanaryDeployment(e){let n=e.strategy||"BALANCED",r=Zi.Strategies[n].map((i)=>({...i,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:r,currentStage:0,status:"pending",autoPromote:e.autoPromote??!0,autoRollback:!0})}createECSCanaryDeployment(e){let n=e.strategy||"CONSERVATIVE",r=Zi.Strategies[n];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:r,currentStage:0,status:"pending",autoRollback:!0})}async executeDeployment(e,n=!1){let r=this.deployments.get(e);if(!r)throw Error(`Deployment not found: ${e}`);let i={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,completedStages:0,rolledBack:!1};console.log(`${n?"[DRY RUN] ":""}Starting canary deployment: ${r.name}`),console.log(` Strategy: ${r.stages.length} stages`),console.log(` Auto-promote: ${r.autoPromote}`),console.log(` Auto-rollback: ${r.autoRollback}`),console.log(""),r.status="in_progress";for(let s=0;s<r.stages.length;s++){let a=r.stages[s];if(r.currentStage=s,console.log(`Stage ${s+1}/${r.stages.length}: ${a.name}`),console.log(` Traffic: ${a.trafficPercentage}% canary, ${100-a.trafficPercentage}% baseline`),console.log(` Duration: ${a.durationMinutes} minutes`),!n)r.baselineVersion.weight=100-a.trafficPercentage,r.canaryVersion.weight=a.trafficPercentage;if(!await this.monitorStage(r,a,n)){if(console.log(" ✗ Stage failed - metrics exceeded thresholds"),r.autoRollback)console.log("\\n Rolling back deployment..."),await this.rollback(e,n),i.rolledBack=!0,i.reason="Metrics exceeded thresholds";return i.endTime=new Date,r.status="rolled_back",this.recordDeployment(e,i),i}console.log(" ✓ Stage completed successfully"),i.completedStages++,console.log("")}return r.status="completed",i.success=!0,i.endTime=new Date,console.log("✓ Canary deployment completed successfully"),this.recordDeployment(e,i),i}async monitorStage(e,n,r){if(console.log(" Monitoring metrics..."),r)return console.log(" [SKIPPED - DRY RUN]"),!0;await new Promise((s)=>setTimeout(s,100));let i={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)*n.trafficPercentage/100)};if(e.metrics=i,console.log(` Baseline: ${i.baselineErrorRate.toFixed(2)}% errors, ${i.baselineLatencyP99.toFixed(0)}ms P99`),console.log(` Canary: ${i.canaryErrorRate.toFixed(2)}% errors, ${i.canaryLatencyP99.toFixed(0)}ms P99`),n.alarmThresholds){let{errorRate:s,latencyP99:a}=n.alarmThresholds;if(s&&i.canaryErrorRate>s)return console.log(` ⚠ Error rate exceeded threshold: ${i.canaryErrorRate.toFixed(2)}% > ${s}%`),!1;if(a&&i.canaryLatencyP99>a)return console.log(` ⚠ Latency P99 exceeded threshold: ${i.canaryLatencyP99.toFixed(0)}ms > ${a}ms`),!1}return!0}async rollback(e,n=!1){let r=this.deployments.get(e);if(!r)throw Error(`Deployment not found: ${e}`);if(console.log(`${n?"[DRY RUN] ":""}Rolling back canary deployment: ${r.name}`),!n)r.baselineVersion.weight=100,r.canaryVersion.weight=0,r.status="rolled_back";console.log(" Traffic restored to baseline: 100%")}promoteCanary(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);console.log(`Promoting canary to baseline: ${n.name}`);let r=n.baselineVersion;n.baselineVersion=n.canaryVersion,n.canaryVersion=r,n.baselineVersion.weight=100,n.canaryVersion.weight=0,n.status="completed",console.log(" Canary promoted successfully")}recordDeployment(e,n){if(!this.deploymentHistory.has(e))this.deploymentHistory.set(e,[]);this.deploymentHistory.get(e).push(n)}getDeployment(e){return this.deployments.get(e)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(e){return this.deploymentHistory.get(e)||[]}generateLambdaAliasCF(e,n){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:{Ref:"LambdaFunction"},Name:n,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 Tp=new Zi;class Qa{tests=new Map;testCounter=0;createTest(e){let n=`abtest-${Date.now()}-${this.testCounter++}`,r={id:n,...e};return this.tests.set(n,r),r}createSimpleABTest(e){let n=e.variantTrafficPercentage||50;return this.createTest({name:e.name,description:e.description,variants:[{id:"control",name:"Control",description:"Original version",trafficPercentage:100-n,targetGroupArn:e.controlTargetGroupArn,weight:100-n},{id:"variant-a",name:"Variant A",description:"Test version",trafficPercentage:n,targetGroupArn:e.variantTargetGroupArn,weight:n}],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 n=e.variants.reduce((r,i)=>r+i.trafficPercentage,0);if(n!==100)throw Error(`Traffic percentages must sum to 100, got ${n}`);return this.createTest({name:e.name,description:e.description,variants:e.variants.map((r,i)=>({id:`variant-${i}`,name:r.name,description:r.description,trafficPercentage:r.trafficPercentage,targetGroupArn:r.targetGroupArn,weight:r.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 n=this.tests.get(e);if(!n)throw Error(`Test not found: ${e}`);if(n.status!=="draft"&&n.status!=="paused")throw Error(`Cannot start test in ${n.status} status`);n.status="active",n.startTime=new Date,console.log(`Started A/B test: ${n.name}`),console.log(` Variants: ${n.variants.length}`),n.variants.forEach((r)=>{console.log(` - ${r.name}: ${r.trafficPercentage}%`)})}pauseTest(e){let n=this.tests.get(e);if(!n)throw Error(`Test not found: ${e}`);n.status="paused",console.log(`Paused A/B test: ${n.name}`)}updateTrafficSplit(e,n,r){let i=this.tests.get(e);if(!i)throw Error(`Test not found: ${e}`);let s=i.variants.find((c)=>c.id===n);if(!s)throw Error(`Variant not found: ${n}`);let a=s.trafficPercentage;s.trafficPercentage=r,s.weight=r,console.log(`Updated ${s.name} traffic: ${a}% → ${r}%`)}analyzeResults(e){let n=this.tests.get(e);if(!n)throw Error(`Test not found: ${e}`);if(!n.metrics)n.metrics=this.collectMetrics(n);let r=n.variants[0],i=0;for(let m of n.variants){let p=n.metrics.variants[m.id];if(p&&p.conversionRate>i)i=p.conversionRate,r=m}let s=n.metrics.variants.control||n.metrics.variants[n.variants[0].id],a=n.metrics.variants[r.id],c=(a.conversionRate-s.conversionRate)/s.conversionRate*100,u=100,d=a.requests>u&&s.requests>u&&Math.abs(c)>10;return{testId:e,winningVariant:r.name,confidence:d?95:75,improvement:c,statisticalSignificance:d,metrics:n.metrics,recommendation:this.generateRecommendation(c,d,r.name)}}declareWinner(e,n){let r=this.tests.get(e);if(!r)throw Error(`Test not found: ${e}`);let i=r.variants.find((s)=>s.id===n);if(!i)throw Error(`Variant not found: ${n}`);r.variants.forEach((s)=>{if(s.id===n)s.trafficPercentage=100,s.weight=100;else s.trafficPercentage=0,s.weight=0}),r.status="completed",r.endTime=new Date,r.winner=n,console.log(`Declared winner: ${i.name}`),console.log(` All traffic now routed to ${i.name}`)}collectMetrics(e){let n={},r=0;for(let i of e.variants){let s=Math.floor(Math.random()*1000)+500,a=Math.floor(s*(Math.random()*0.1+0.05)),c=a/s*100;n[i.id]={requests:s,conversions:a,conversionRate:c,averageLatency:150+Math.random()*100,errorRate:Math.random()*0.5,revenue:a*(Math.random()*50+100)},r+=s}return{variants:n,totalRequests:r,startTime:e.startTime,lastUpdated:new Date}}generateRecommendation(e,n,r){if(!n)return"Continue test - sample size too small or no significant difference detected";if(e>20)return`Strong winner detected - ${r} shows ${e.toFixed(1)}% improvement. Recommend deploying to all traffic.`;if(e>10)return`Moderate improvement - ${r} shows ${e.toFixed(1)}% improvement. Consider deploying.`;if(e>0)return`Minor improvement - ${r} 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((n)=>({TargetGroupArn:n.targetGroupArn,Weight:n.weight})),TargetGroupStickinessConfig:{Enabled:e.routingStrategy.stickySession||!1,DurationSeconds:e.routingStrategy.sessionDuration?e.routingStrategy.sessionDuration*60:void 0}}}]}}}generateLambdaEdgeFunction(e){return`'use strict';
|
|
3576
3574
|
|
|
3577
3575
|
exports.handler = (event, _context, _callback) => {
|
|
3578
3576
|
const request = event.Records[0].cf.request;
|
|
@@ -3619,7 +3617,7 @@ exports.handler = (event, _context, _callback) => {
|
|
|
3619
3617
|
}`).join(" else ")}
|
|
3620
3618
|
|
|
3621
3619
|
callback(null, request);
|
|
3622
|
-
};`}clear(){this.tests.clear(),this.testCounter=0}}var up=new za;class Ha{rollouts=new Map;flags=new Map;gates=new Map;counter=0;createProgressiveRollout(e,n){let r=`rollout-${Date.now()}-${this.counter++}`,i={id:r,name:e,stages:n,currentStage:0};return this.rollouts.set(r,i),i}createFeatureFlag(e,n=0){let r=`flag-${Date.now()}-${this.counter++}`,i={id:r,name:e,enabled:!1,rolloutPercentage:n,targetingRules:[]};return this.flags.set(r,i),i}createDeploymentGate(e,n,r,i){let s=`gate-${Date.now()}-${this.counter++}`,a={id:s,name:e,type:n,approvers:r,conditions:i};return this.gates.set(s,a),a}clear(){this.rollouts.clear(),this.flags.clear(),this.gates.clear()}}var pp=new Ha;class Ll{configs=new Map;samplingRules=new Map;configCounter=0;ruleCounter=0;createConfig(e){let n=`xray-config-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.configs.set(n,r),r}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 n=`sampling-rule-${Date.now()}-${this.ruleCounter++}`,r={id:n,...e};return this.samplingRules.set(n,r),r}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,n=0.05){return this.createSamplingRule({ruleName:`${e}-default`,priority:1000,fixedRate:n,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,n){return{id:`trace-${Date.now()}-${this.configCounter++}`,traceId:e,spans:n}}clear(){this.configs.clear(),this.samplingRules.clear(),this.configCounter=0,this.ruleCounter=0}}var Ff=new Ll;class Ml{namespaces=new Map;metrics=new Map;namespaceCounter=0;metricCounter=0;alarmCounter=0;createNamespace(e){let n=`namespace-${Date.now()}-${this.namespaceCounter++}`,r={id:n,...e};return this.namespaces.set(n,r),r}createMetric(e){let n=`metric-${Date.now()}-${this.metricCounter++}`,r={id:n,...e};return this.metrics.set(n,r),r}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,n){let r=this.metrics.get(e);if(!r)throw Error(`Metric not found: ${e}`);let s={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...n};if(!r.alarms)r.alarms=[];return r.alarms.push(s),s}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,n){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:n.name,AlarmDescription:n.description,ComparisonOperator:n.comparisonOperator,EvaluationPeriods:n.evaluationPeriods,MetricName:e.name,Namespace:e.namespace,Period:n.period,Statistic:n.statistic,Threshold:n.threshold,TreatMissingData:n.treatMissingData||"notBreaching",ActionsEnabled:n.actionsEnabled??!0,...n.alarmActions&&{AlarmActions:n.alarmActions},...n.okActions&&{OKActions:n.okActions},...n.insufficientDataActions&&{InsufficientDataActions:n.insufficientDataActions},...e.dimensions&&{Dimensions:e.dimensions.map((r)=>({Name:r.name,Value:r.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((n)=>[n.name,n.value])||[]]],period:300,stat:"Average",region:"us-east-1",title:e.name}}}publishCustomMetric(e,n,r,i={},s="Count"){return{id:`metric-${Date.now()}-${this.metricCounter++}`,namespace:e,name:n,dimensions:i,value:r,unit:s,timestamp:new Date}}clear(){this.namespaces.clear(),this.metrics.clear(),this.namespaceCounter=0,this.metricCounter=0,this.alarmCounter=0}}var jf=new Ml;class Ga{logGroups=new Map;queries=new Map;insightsQueries=new Map;logGroupCounter=0;filterCounter=0;queryCounter=0;createLogGroup(e){let n=`log-group-${Date.now()}-${this.logGroupCounter++}`,r={id:n,...e};return this.logGroups.set(n,r),r}createLambdaLogGroup(e,n=7){return this.createLogGroup({name:`/aws/lambda/${e}`,retentionDays:n})}createECSLogGroup(e){return this.createLogGroup({name:`/ecs/${e.clusterName}/${e.serviceName}`,retentionDays:e.retentionDays||14})}createAPIGatewayLogGroup(e,n,r=30){return this.createLogGroup({name:`/aws/apigateway/${e}/${n}`,retentionDays:r})}createApplicationLogGroup(e){return this.createLogGroup({name:`/application/${e.appName}/${e.environment}`,retentionDays:e.retentionDays||30,kmsKeyId:e.kmsKeyId})}createMetricFilter(e,n){let r=this.logGroups.get(e);if(!r)throw Error(`Log group not found: ${e}`);let s={id:`filter-${Date.now()}-${this.filterCounter++}`,...n};if(!r.metricFilters)r.metricFilters=[];return r.metricFilters.push(s),s}createErrorCountFilter(e,n){return this.createMetricFilter(e,{name:"ErrorCount",filterPattern:"[timestamp, request_id, level = ERROR*, ...]",metricTransformations:[{metricName:"ErrorCount",metricNamespace:n,metricValue:"1",defaultValue:0,unit:"Count"}]})}createLatencyFilter(e,n){return this.createMetricFilter(e,{name:"Latency",filterPattern:"[timestamp, request_id, level, duration, ...]",metricTransformations:[{metricName:"ResponseTime",metricNamespace:n,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,n){let r=this.logGroups.get(e);if(!r)throw Error(`Log group not found: ${e}`);let s={id:`subscription-${Date.now()}-${this.filterCounter++}`,...n};if(!r.subscriptionFilters)r.subscriptionFilters=[];return r.subscriptionFilters.push(s),s}createKinesisSubscription(e){let n=this.logGroups.get(e.logGroupId);if(!n)throw Error(`Log group not found: ${e.logGroupId}`);return this.createSubscriptionFilter(e.logGroupId,{name:"KinesisSubscription",logGroupName:n.name,filterPattern:e.filterPattern||"",destinationArn:e.kinesisStreamArn,roleArn:e.roleArn,distribution:"Random"})}createLambdaSubscription(e){let n=this.logGroups.get(e.logGroupId);if(!n)throw Error(`Log group not found: ${e.logGroupId}`);return this.createSubscriptionFilter(e.logGroupId,{name:"LambdaSubscription",logGroupName:n.name,filterPattern:e.filterPattern||"",destinationArn:e.lambdaFunctionArn,distribution:"ByLogStream"})}createInsightsQuery(e){let n=`query-${Date.now()}-${this.queryCounter++}`,r={id:n,...e};return this.insightsQueries.set(n,r),r}createErrorAnalysisQuery(e){return this.createInsightsQuery({name:"Error Analysis",description:"Analyze error patterns and frequencies",query:`fields @timestamp, @message
|
|
3620
|
+
};`}clear(){this.tests.clear(),this.testCounter=0}}var Ep=new Qa;class Ya{rollouts=new Map;flags=new Map;gates=new Map;counter=0;createProgressiveRollout(e,n){let r=`rollout-${Date.now()}-${this.counter++}`,i={id:r,name:e,stages:n,currentStage:0};return this.rollouts.set(r,i),i}createFeatureFlag(e,n=0){let r=`flag-${Date.now()}-${this.counter++}`,i={id:r,name:e,enabled:!1,rolloutPercentage:n,targetingRules:[]};return this.flags.set(r,i),i}createDeploymentGate(e,n,r,i){let s=`gate-${Date.now()}-${this.counter++}`,a={id:s,name:e,type:n,approvers:r,conditions:i};return this.gates.set(s,a),a}clear(){this.rollouts.clear(),this.flags.clear(),this.gates.clear()}}var wp=new Ya;class ql{configs=new Map;samplingRules=new Map;configCounter=0;ruleCounter=0;createConfig(e){let n=`xray-config-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.configs.set(n,r),r}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 n=`sampling-rule-${Date.now()}-${this.ruleCounter++}`,r={id:n,...e};return this.samplingRules.set(n,r),r}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,n=0.05){return this.createSamplingRule({ruleName:`${e}-default`,priority:1000,fixedRate:n,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,n){return{id:`trace-${Date.now()}-${this.configCounter++}`,traceId:e,spans:n}}clear(){this.configs.clear(),this.samplingRules.clear(),this.configCounter=0,this.ruleCounter=0}}var Zf=new ql;class Wl{namespaces=new Map;metrics=new Map;namespaceCounter=0;metricCounter=0;alarmCounter=0;createNamespace(e){let n=`namespace-${Date.now()}-${this.namespaceCounter++}`,r={id:n,...e};return this.namespaces.set(n,r),r}createMetric(e){let n=`metric-${Date.now()}-${this.metricCounter++}`,r={id:n,...e};return this.metrics.set(n,r),r}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,n){let r=this.metrics.get(e);if(!r)throw Error(`Metric not found: ${e}`);let s={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...n};if(!r.alarms)r.alarms=[];return r.alarms.push(s),s}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,n){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:n.name,AlarmDescription:n.description,ComparisonOperator:n.comparisonOperator,EvaluationPeriods:n.evaluationPeriods,MetricName:e.name,Namespace:e.namespace,Period:n.period,Statistic:n.statistic,Threshold:n.threshold,TreatMissingData:n.treatMissingData||"notBreaching",ActionsEnabled:n.actionsEnabled??!0,...n.alarmActions&&{AlarmActions:n.alarmActions},...n.okActions&&{OKActions:n.okActions},...n.insufficientDataActions&&{InsufficientDataActions:n.insufficientDataActions},...e.dimensions&&{Dimensions:e.dimensions.map((r)=>({Name:r.name,Value:r.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((n)=>[n.name,n.value])||[]]],period:300,stat:"Average",region:"us-east-1",title:e.name}}}publishCustomMetric(e,n,r,i={},s="Count"){return{id:`metric-${Date.now()}-${this.metricCounter++}`,namespace:e,name:n,dimensions:i,value:r,unit:s,timestamp:new Date}}clear(){this.namespaces.clear(),this.metrics.clear(),this.namespaceCounter=0,this.metricCounter=0,this.alarmCounter=0}}var eh=new Wl;class Za{logGroups=new Map;queries=new Map;insightsQueries=new Map;logGroupCounter=0;filterCounter=0;queryCounter=0;createLogGroup(e){let n=`log-group-${Date.now()}-${this.logGroupCounter++}`,r={id:n,...e};return this.logGroups.set(n,r),r}createLambdaLogGroup(e,n=7){return this.createLogGroup({name:`/aws/lambda/${e}`,retentionDays:n})}createECSLogGroup(e){return this.createLogGroup({name:`/ecs/${e.clusterName}/${e.serviceName}`,retentionDays:e.retentionDays||14})}createAPIGatewayLogGroup(e,n,r=30){return this.createLogGroup({name:`/aws/apigateway/${e}/${n}`,retentionDays:r})}createApplicationLogGroup(e){return this.createLogGroup({name:`/application/${e.appName}/${e.environment}`,retentionDays:e.retentionDays||30,kmsKeyId:e.kmsKeyId})}createMetricFilter(e,n){let r=this.logGroups.get(e);if(!r)throw Error(`Log group not found: ${e}`);let s={id:`filter-${Date.now()}-${this.filterCounter++}`,...n};if(!r.metricFilters)r.metricFilters=[];return r.metricFilters.push(s),s}createErrorCountFilter(e,n){return this.createMetricFilter(e,{name:"ErrorCount",filterPattern:"[timestamp, request_id, level = ERROR*, ...]",metricTransformations:[{metricName:"ErrorCount",metricNamespace:n,metricValue:"1",defaultValue:0,unit:"Count"}]})}createLatencyFilter(e,n){return this.createMetricFilter(e,{name:"Latency",filterPattern:"[timestamp, request_id, level, duration, ...]",metricTransformations:[{metricName:"ResponseTime",metricNamespace:n,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,n){let r=this.logGroups.get(e);if(!r)throw Error(`Log group not found: ${e}`);let s={id:`subscription-${Date.now()}-${this.filterCounter++}`,...n};if(!r.subscriptionFilters)r.subscriptionFilters=[];return r.subscriptionFilters.push(s),s}createKinesisSubscription(e){let n=this.logGroups.get(e.logGroupId);if(!n)throw Error(`Log group not found: ${e.logGroupId}`);return this.createSubscriptionFilter(e.logGroupId,{name:"KinesisSubscription",logGroupName:n.name,filterPattern:e.filterPattern||"",destinationArn:e.kinesisStreamArn,roleArn:e.roleArn,distribution:"Random"})}createLambdaSubscription(e){let n=this.logGroups.get(e.logGroupId);if(!n)throw Error(`Log group not found: ${e.logGroupId}`);return this.createSubscriptionFilter(e.logGroupId,{name:"LambdaSubscription",logGroupName:n.name,filterPattern:e.filterPattern||"",destinationArn:e.lambdaFunctionArn,distribution:"ByLogStream"})}createInsightsQuery(e){let n=`query-${Date.now()}-${this.queryCounter++}`,r={id:n,...e};return this.insightsQueries.set(n,r),r}createErrorAnalysisQuery(e){return this.createInsightsQuery({name:"Error Analysis",description:"Analyze error patterns and frequencies",query:`fields @timestamp, @message
|
|
3623
3621
|
| filter @message like /ERROR/
|
|
3624
3622
|
| stats count() by bin(5m)
|
|
3625
3623
|
| sort @timestamp desc`,logGroupNames:e})}createLatencyAnalysisQuery(e){return this.createInsightsQuery({name:"Latency Analysis",description:"Analyze request latency patterns",query:`fields @timestamp, @duration
|
|
@@ -3629,7 +3627,7 @@ exports.handler = (event, _context, _callback) => {
|
|
|
3629
3627
|
| filter @message like /ERROR/
|
|
3630
3628
|
| stats count() as error_count by @message
|
|
3631
3629
|
| sort error_count desc
|
|
3632
|
-
| 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,n){return{Type:"AWS::Logs::MetricFilter",Properties:{FilterName:n.name,FilterPattern:n.filterPattern,LogGroupName:e.name,MetricTransformations:n.metricTransformations.map((r)=>({MetricName:r.metricName,MetricNamespace:r.metricNamespace,MetricValue:r.metricValue,...r.defaultValue!==void 0&&{DefaultValue:r.defaultValue},...r.unit&&{Unit:r.unit},...r.dimensions&&{Dimensions:r.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,n,r=7){let i=`aggregation-${Date.now()}-${this.logGroupCounter++}`,s=this.createLogGroup({name:e,retentionDays:r});return n.forEach((a)=>{this.createMetricFilter(s.id,{name:a.metric,filterPattern:a.pattern,metricTransformations:[{metricName:a.metric,metricNamespace:"CustomMetrics",metricValue:"1",defaultValue:0,unit:"Count"}]})}),{id:i,logGroup:e,filters:n,retention:r}}clear(){this.logGroups.clear(),this.queries.clear(),this.insightsQueries.clear(),this.logGroupCounter=0,this.filterCounter=0,this.queryCounter=0}}var
|
|
3630
|
+
| 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,n){return{Type:"AWS::Logs::MetricFilter",Properties:{FilterName:n.name,FilterPattern:n.filterPattern,LogGroupName:e.name,MetricTransformations:n.metricTransformations.map((r)=>({MetricName:r.metricName,MetricNamespace:r.metricNamespace,MetricValue:r.metricValue,...r.defaultValue!==void 0&&{DefaultValue:r.defaultValue},...r.unit&&{Unit:r.unit},...r.dimensions&&{Dimensions:r.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,n,r=7){let i=`aggregation-${Date.now()}-${this.logGroupCounter++}`,s=this.createLogGroup({name:e,retentionDays:r});return n.forEach((a)=>{this.createMetricFilter(s.id,{name:a.metric,filterPattern:a.pattern,metricTransformations:[{metricName:a.metric,metricNamespace:"CustomMetrics",metricValue:"1",defaultValue:0,unit:"Count"}]})}),{id:i,logGroup:e,filters:n,retention:r}}clear(){this.logGroups.clear(),this.queries.clear(),this.insightsQueries.clear(),this.logGroupCounter=0,this.filterCounter=0,this.queryCounter=0}}var Ap=new Za;class qr{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 n=`canary-${Date.now()}-${this.canaryCounter++}`,r={id:n,...e};return this.canaries.set(n,r),r}createHeartbeatCanary(e){let n=`
|
|
3633
3631
|
const synthetics = require('Synthetics');
|
|
3634
3632
|
const log = require('SyntheticsLogger');
|
|
3635
3633
|
|
|
@@ -3649,7 +3647,7 @@ const heartbeat = async function () {
|
|
|
3649
3647
|
exports.handler = async () => {
|
|
3650
3648
|
return await heartbeat();
|
|
3651
3649
|
};
|
|
3652
|
-
`;return this.createCanary({name:e.name,description:`Heartbeat monitor for ${e.url}`,runtimeVersion:
|
|
3650
|
+
`;return this.createCanary({name:e.name,description:`Heartbeat monitor for ${e.url}`,runtimeVersion:qr.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:n},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:60,memoryInMB:960,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}createAPICanary(e){let r=`
|
|
3653
3651
|
const synthetics = require('Synthetics');
|
|
3654
3652
|
const log = require('SyntheticsLogger');
|
|
3655
3653
|
|
|
@@ -3678,7 +3676,7 @@ const apiCheck = async function () {
|
|
|
3678
3676
|
exports.handler = async () => {
|
|
3679
3677
|
return await apiCheck();
|
|
3680
3678
|
};
|
|
3681
|
-
`;return this.createCanary({name:e.name,description:`API monitor for ${e.baseUrl}`,runtimeVersion:
|
|
3679
|
+
`;return this.createCanary({name:e.name,description:`API monitor for ${e.baseUrl}`,runtimeVersion:qr.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:r},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:120,memoryInMB:960,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}createVisualRegressionCanary(e){let n=`
|
|
3682
3680
|
const synthetics = require('Synthetics');
|
|
3683
3681
|
const log = require('SyntheticsLogger');
|
|
3684
3682
|
|
|
@@ -3698,7 +3696,7 @@ const visualCheck = async function () {
|
|
|
3698
3696
|
exports.handler = async () => {
|
|
3699
3697
|
return await visualCheck();
|
|
3700
3698
|
};
|
|
3701
|
-
`;return this.createCanary({name:e.name,description:`Visual regression monitor for ${e.url}`,runtimeVersion:
|
|
3699
|
+
`;return this.createCanary({name:e.name,description:`Visual regression monitor for ${e.url}`,runtimeVersion:qr.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:n},schedule:{expression:`rate(${e.interval} minutes)`},runConfig:{timeoutInSeconds:120,memoryInMB:1024,activeTracing:!0},artifactS3Location:`s3://${e.s3Bucket}/canary-artifacts/${e.name}/`,successRetentionPeriod:31,failureRetentionPeriod:31})}createWorkflowCanary(e){let r=`
|
|
3702
3700
|
const synthetics = require('Synthetics');
|
|
3703
3701
|
const log = require('SyntheticsLogger');
|
|
3704
3702
|
|
|
@@ -3720,35 +3718,35 @@ const workflowCheck = async function () {
|
|
|
3720
3718
|
exports.handler = async () => {
|
|
3721
3719
|
return await workflowCheck();
|
|
3722
3720
|
};
|
|
3723
|
-
`;return this.createCanary({name:e.name,description:e.description,runtimeVersion:
|
|
3721
|
+
`;return this.createCanary({name:e.name,description:e.description,runtimeVersion:qr.RuntimeVersions.NODEJS_PUPPETEER_4_0,handler:"index.handler",code:{type:"script",script:r},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,n){let r=this.canaries.get(e);if(!r)throw Error(`Canary not found: ${e}`);let s={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...n};if(!r.alarms)r.alarms=[];return r.alarms.push(s),s}getCanary(e){return this.canaries.get(e)}listCanaries(){return Array.from(this.canaries.values())}generateCanaryCF(e){let n={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")n.Properties.Code={Handler:e.handler,Script:e.code.script};else n.Properties.Code={Handler:e.handler,S3Bucket:e.code.s3Bucket,S3Key:e.code.s3Key,...e.code.s3Version&&{S3ObjectVersion:e.code.s3Version}};if(e.runConfig)n.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)n.Properties.VPCConfig={SubnetIds:e.vpcConfig.subnetIds,SecurityGroupIds:e.vpcConfig.securityGroupIds};if(e.successRetentionPeriod)n.Properties.SuccessRetentionPeriod=e.successRetentionPeriod;if(e.failureRetentionPeriod)n.Properties.FailureRetentionPeriod=e.failureRetentionPeriod;return n}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 Rp=new qr;class Kl{plans=new Map;migrations=new Map;planCounter=0;migrationCounter=0;createPlan(e){let n=`migration-plan-${Date.now()}-${this.planCounter++}`,r={id:n,...e};return this.plans.set(n,r),r}createMigration(e){let n=`migration-${Date.now()}-${this.migrationCounter++}`,r=this.generateChecksum(e.up+e.down),i={id:n,checksum:r,...e};return this.migrations.set(n,i),i}createSchemaMigration(e){let{up:n,down:r}=this.generateSchemaSQL(e.changes,e.tableName,e.engine);return this.createMigration({version:e.version,name:e.name,description:`Schema changes for ${e.tableName}`,up:n,down:r})}createDataMigration(e){return this.createMigration({version:e.version,name:e.name,description:e.description,up:e.upSQL,down:e.downSQL})}addMigrationToPlan(e,n){let r=this.plans.get(e);if(!r)throw Error(`Migration plan not found: ${e}`);r.migrations.push(n)}async executePlan(e,n=!1){let r=this.plans.get(e);if(!r)throw Error(`Migration plan not found: ${e}`);let i=Date.now(),s=[],a=[];if(console.log(`${n?"[DRY RUN] ":""}Executing migration plan: ${r.name}`),console.log(`Database: ${r.database.type} - ${r.database.identifier}`),console.log(`Migrations to apply: ${r.migrations.length}
|
|
3724
3722
|
`),r.backupBeforeMigration&&!n)console.log("Creating database backup before migration...");for(let u of r.migrations)try{if(console.log(`Applying migration: ${u.version} - ${u.name}`),!n){if(this.generateChecksum(u.up+u.down)!==u.checksum)throw Error("Migration checksum mismatch - migration has been modified");let m=Date.now();u.appliedAt=new Date,u.executionTimeMs=Date.now()-m,console.log(`✓ Applied in ${u.executionTimeMs}ms
|
|
3725
3723
|
`)}else console.log(`[SKIPPED - DRY RUN]
|
|
3726
3724
|
`);s.push(u.version)}catch(d){if(console.error(`✗ Failed: ${d instanceof Error?d.message:String(d)}
|
|
3727
3725
|
`),a.push(u.version),!n)return console.log("Rolling back previously applied migrations..."),await this.rollbackMigrations(s.reverse(),r),{success:!1,version:u.version,appliedMigrations:[],failedMigrations:a,executionTimeMs:Date.now()-i,error:d instanceof Error?d.message:String(d),rollbackPerformed:!0}}let c=Date.now()-i;return console.log(`${n?"[DRY RUN] ":""}Migration plan completed successfully`),console.log(`Total time: ${c}ms`),{success:!0,version:r.migrations[r.migrations.length-1]?.version||"unknown",appliedMigrations:s,failedMigrations:a,executionTimeMs:c}}async rollbackMigrations(e,n){for(let r of e){let i=n.migrations.find((s)=>s.version===r);if(i)console.log(`Rolling back: ${i.version} - ${i.name}`),i.rolledBackAt=new Date,console.log(`✓ Rolled back
|
|
3728
3726
|
`)}}getMigrationStatus(e){let n=this.plans.get(e);if(!n)throw Error(`Migration plan not found: ${e}`);let r=n.migrations.filter((s)=>s.appliedAt&&!s.rolledBackAt),i=n.migrations.filter((s)=>!s.appliedAt);return{currentVersion:r[r.length-1]?.version||"0.0.0",pendingMigrations:i,appliedMigrations:r,lastMigration:r[r.length-1]}}generateSchemaSQL(e,n,r="postgres"){let i=[],s=[];for(let a of e)switch(a.type){case"add_column":i.push(`ALTER TABLE ${n} ADD COLUMN ${a.columnName} ${a.columnType}${a.nullable===!1?" NOT NULL":""}${a.defaultValue?` DEFAULT ${a.defaultValue}`:""}; `),s.push(`ALTER TABLE ${n} DROP COLUMN ${a.columnName};`);break;case"drop_column":i.push(`ALTER TABLE ${n} DROP COLUMN ${a.columnName};`),s.push(`-- Cannot restore dropped column ${a.columnName}`);break;case"modify_column":if(r==="postgres")i.push(`ALTER TABLE ${n} ALTER COLUMN ${a.columnName} TYPE ${a.newType};`);else i.push(`ALTER TABLE ${n} MODIFY COLUMN ${a.columnName} ${a.newType};`);s.push(`-- Reverting ${a.columnName} type change requires manual intervention`);break;case"add_index":i.push(`CREATE INDEX ${a.indexName} ON ${n} (${(a.columns??[]).join(", ")});`),s.push(`DROP INDEX ${a.indexName};`);break;case"drop_index":i.push(`DROP INDEX ${a.indexName};`),s.push(`-- Cannot restore index ${a.indexName} without schema details`);break}return{up:i.join(`
|
|
3729
3727
|
`),down:s.reverse().join(`
|
|
3730
|
-
`)}}generateChecksum(e){let n=0;for(let r=0;r<e.length;r++){let i=e.charCodeAt(r);n=(n<<5)-n+i,n=n&n}return n.toString(16)}validatePlan(e){let n=this.plans.get(e);if(!n)return{valid:!1,errors:["Migration plan not found"]};let r=[],i=new Set;for(let s of n.migrations){if(i.has(s.version))r.push(`Duplicate migration version: ${s.version}`);i.add(s.version)}for(let s of n.migrations)if(!s.down||s.down.trim()==="")r.push(`Migration ${s.version} is missing rollback SQL`);for(let s of n.migrations)if(this.generateChecksum(s.up+s.down)!==s.checksum)r.push(`Migration ${s.version} has invalid checksum`);return{valid:r.length===0,errors:r}}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
|
|
3728
|
+
`)}}generateChecksum(e){let n=0;for(let r=0;r<e.length;r++){let i=e.charCodeAt(r);n=(n<<5)-n+i,n=n&n}return n.toString(16)}validatePlan(e){let n=this.plans.get(e);if(!n)return{valid:!1,errors:["Migration plan not found"]};let r=[],i=new Set;for(let s of n.migrations){if(i.has(s.version))r.push(`Duplicate migration version: ${s.version}`);i.add(s.version)}for(let s of n.migrations)if(!s.down||s.down.trim()==="")r.push(`Migration ${s.version} is missing rollback SQL`);for(let s of n.migrations)if(this.generateChecksum(s.up+s.down)!==s.checksum)r.push(`Migration ${s.version} has invalid checksum`);return{valid:r.length===0,errors:r}}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 th=new Kl;class ec{replicas=new Map;replicationGroups=new Map;proxies=new Map;proxyTargets=new Map;replicaCounter=0;groupCounter=0;proxyCounter=0;targetCounter=0;createReplica(e){let n=`replica-${Date.now()}-${this.replicaCounter++}`,r={id:n,status:"creating",...e};return this.replicas.set(n,r),r}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 n=`replication-group-${Date.now()}-${this.groupCounter++}`,r={id:n,...e};return this.replicationGroups.set(n,r),r}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,n){let r=this.replicationGroups.get(e);if(!r)throw Error(`Replication group not found: ${e}`);r.replicas.push(n)}createProxy(e){let n=`rds-proxy-${Date.now()}-${this.proxyCounter++}`,r={id:n,...e};return this.proxies.set(n,r),r}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 n=`proxy-target-${Date.now()}-${this.targetCounter++}`,r={id:n,...e};return this.proxyTargets.set(n,r),r}promoteReplica(e){let n=this.replicas.get(e);if(!n)return{success:!1,message:"Replica not found"};if(console.log(`Promoting replica to primary: ${n.name}`),console.log(`Region: ${n.region}`),console.log(`
|
|
3731
3729
|
1. Checking replication lag...`),n.replicationLag&&n.replicationLag>5000)return{success:!1,message:`Replication lag too high: ${n.replicationLag}ms`};return console.log(` Replication lag: ${n.replicationLag||0}ms (acceptable)`),console.log(`
|
|
3732
3730
|
2. Promoting replica to standalone instance...`),console.log(`
|
|
3733
3731
|
3. Updating DNS records...`),console.log(`
|
|
3734
3732
|
4. Updating application configuration...`),console.log(`
|
|
3735
|
-
✓ Promotion completed successfully`),n.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,n){return{Type:"AWS::RDS::DBProxyTargetGroup",Properties:{DBProxyName:n.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 fp=new qa;class Bl{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 n=`pi-${Date.now()}-${this.insightsCounter++}`,r={id:n,name:e.name,databaseIdentifier:e.databaseIdentifier,enabled:!0,retentionPeriod:e.retentionPeriod||7,kmsKeyId:e.kmsKeyId};return this.insights.set(n,r),r}enableSlowQueryLog(e){let n=`slow-query-${Date.now()}-${this.logCounter++}`,r={id:n,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(n,r),r}recordQueryMetric(e){let n=`metric-${Date.now()}-${this.metricCounter++}`,r={id:n,timestamp:new Date,...e};return this.queryMetrics.set(n,r),r}generatePerformanceReport(e){let n=`report-${Date.now()}-${this.reportCounter++}`,r={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)},i=Array.from(this.queryMetrics.values()),s=i.sort((d,m)=>m.executionCount-d.executionCount).slice(0,10),a=i.filter((d)=>d.avgExecutionTime>1000).sort((d,m)=>m.avgExecutionTime-d.avgExecutionTime).slice(0,10),c=this.generateRecommendations(r,a),u={id:n,name:e.name,databaseIdentifier:e.databaseIdentifier,reportType:e.reportType,metrics:r,topQueries:s,slowQueries:a,recommendations:c,generatedAt:new Date};return this.reports.set(n,u),u}generateRecommendations(e,n){let r=[];if(e.avgCPU>70)r.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)r.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)r.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(n.length>0)r.push({type:"index",severity:"high",title:"Slow Queries Detected",description:`${n.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)r.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 r}analyzeQuery(e){let n=`analysis-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,r=[{id:1,operation:"Seq Scan",table:"users",rows:1e4,cost:850.5,children:[]}],i=[];if(e.toLowerCase().includes("select *"))i.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"))i.push({type:"full_table_scan",severity:"critical",description:"Query has no WHERE clause and may scan entire table."});return{id:n,queryId:n,sql:e,executionPlan:r,bottlenecks:i,recommendations:["Add appropriate indexes on WHERE clause columns","Consider using EXPLAIN ANALYZE to get actual execution statistics","Review and optimize JOIN conditions"],estimatedCost:r[0].cost}}recommendIndex(e){let n=`index-rec-${Date.now()}-${this.recommendationCounter++}`,r=`idx_${e.tableName}_${e.columns.join("_")}`,i={id:n,tableName:e.tableName,columns:e.columns,reason:e.reason,estimatedImprovement:e.estimatedImprovement||50,estimatedSize:e.columns.length*10,createSQL:`CREATE INDEX ${r} ON ${e.tableName} (${e.columns.join(", ")});`};return this.indexRecommendations.set(n,i),i}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 zf=new Bl;class Fl{users=new Map;roles=new Map;audits=new Map;userCounter=0;roleCounter=0;auditCounter=0;createUser(e){let n=`db-user-${Date.now()}-${this.userCounter++}`,r={id:n,createdAt:new Date,...e};return this.users.set(n,r),r}createReadOnlyUser(e){let n=e.tables?e.tables.map((r)=>({database:e.database,table:r,privileges:["SELECT"]})):[{database:e.database,privileges:["SELECT"]}];return this.createUser({username:e.username,database:e.database,privileges:n,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:90})}createReadWriteUser(e){let n=e.tables?e.tables.map((r)=>({database:e.database,table:r,privileges:["SELECT","INSERT","UPDATE","DELETE"]})):[{database:e.database,privileges:["SELECT","INSERT","UPDATE","DELETE"]}];return this.createUser({username:e.username,database:e.database,privileges:n,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 n=e.tables.map((r)=>({database:e.database,table:r.name,privileges:r.privileges}));return this.createUser({username:e.username,database:e.database,privileges:n,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:90})}createRole(e){let n=`role-${Date.now()}-${this.roleCounter++}`,r={id:n,users:[],...e};return this.roles.set(n,r),r}assignUserToRole(e,n){let r=this.users.get(e),i=this.roles.get(n);if(!r)throw Error(`User not found: ${e}`);if(!i)throw Error(`Role not found: ${n}`);i.users.push(e);for(let s of i.privileges){let a=r.privileges.find((c)=>c.database===s.database&&c.table===s.table);if(a)a.privileges=Array.from(new Set([...a.privileges,...s.privileges]));else r.privileges.push({...s})}}grantPrivileges(e,n){let r=this.users.get(e);if(!r)return{success:!1,message:"User not found"};for(let i of n){let s=r.privileges.find((a)=>a.database===i.database&&a.table===i.table);if(s)s.privileges=Array.from(new Set([...s.privileges,...i.privileges]));else r.privileges.push(i)}return this.auditAccess({username:r.username,action:"GRANT",database:n[0]?.database,table:n[0]?.table,success:!0}),{success:!0,message:"Privileges granted successfully"}}revokePrivileges(e,n){let r=this.users.get(e);if(!r)return{success:!1,message:"User not found"};for(let i of n){let s=r.privileges.findIndex((a)=>a.database===i.database&&a.table===i.table);if(s!==-1){let a=r.privileges[s];if(a.privileges=a.privileges.filter((c)=>!i.privileges.includes(c)),a.privileges.length===0)r.privileges.splice(s,1)}}return this.auditAccess({username:r.username,action:"REVOKE",database:n[0]?.database,table:n[0]?.table,success:!0}),{success:!0,message:"Privileges revoked successfully"}}rotatePassword(e){let n=this.users.get(e);if(!n)return{success:!1};let r=`arn:aws:secretsmanager:us-east-1:123456789012:secret:db-${n.username}-${Date.now()}`;return n.passwordSecretArn=r,n.lastRotated=new Date,console.log(`Password rotated for user: ${n.username}`),{success:!0,newSecretArn:r}}needsPasswordRotation(e){let n=this.users.get(e);if(!n||!n.rotationEnabled||!n.lastRotated||!n.rotationDays)return!1;return(Date.now()-n.lastRotated.getTime())/86400000>=n.rotationDays}auditAccess(e){let n=`audit-${Date.now()}-${this.auditCounter++}`,r={id:n,timestamp:new Date,...e};return this.audits.set(n,r),r}getUserAccessHistory(e,n=100){return Array.from(this.audits.values()).filter((r)=>r.username===e).sort((r,i)=>i.timestamp.getTime()-r.timestamp.getTime()).slice(0,n)}getFailedLoginAttempts(e,n=24){let r=Date.now()-n*60*60*1000;return Array.from(this.audits.values()).filter((i)=>i.username===e&&i.action==="LOGIN"&&!i.success&&i.timestamp.getTime()>r)}generateCreateUserSQL(e,n="postgres"){let r=[];if(n==="postgres"){r.push(`CREATE USER ${e.username} WITH PASSWORD '${e.passwordSecretArn}';`);for(let i of e.privileges)if(i.privileges.includes("ALL"))r.push(`GRANT ALL PRIVILEGES ON DATABASE ${i.database} TO ${e.username};`);else{let s=i.privileges.join(", ");if(i.table)r.push(`GRANT ${s} ON ${i.database}.${i.table} TO ${e.username};`);else r.push(`GRANT ${s} ON DATABASE ${i.database} TO ${e.username};`)}}else{r.push(`CREATE USER '${e.username}'@'%' IDENTIFIED BY '${e.passwordSecretArn}';`);for(let i of e.privileges){let s=i.privileges.includes("ALL")?"ALL PRIVILEGES":i.privileges.join(", "),a=i.table?`${i.database}.${i.table}`:`${i.database}.*`;r.push(`GRANT ${s} ON ${a} TO '${e.username}'@'%';`)}r.push("FLUSH PRIVILEGES;")}return r.join(`
|
|
3736
|
-
`)}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
|
|
3733
|
+
✓ Promotion completed successfully`),n.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,n){return{Type:"AWS::RDS::DBProxyTargetGroup",Properties:{DBProxyName:n.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 Ip=new ec;class Jl{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 n=`pi-${Date.now()}-${this.insightsCounter++}`,r={id:n,name:e.name,databaseIdentifier:e.databaseIdentifier,enabled:!0,retentionPeriod:e.retentionPeriod||7,kmsKeyId:e.kmsKeyId};return this.insights.set(n,r),r}enableSlowQueryLog(e){let n=`slow-query-${Date.now()}-${this.logCounter++}`,r={id:n,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(n,r),r}recordQueryMetric(e){let n=`metric-${Date.now()}-${this.metricCounter++}`,r={id:n,timestamp:new Date,...e};return this.queryMetrics.set(n,r),r}generatePerformanceReport(e){let n=`report-${Date.now()}-${this.reportCounter++}`,r={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)},i=Array.from(this.queryMetrics.values()),s=i.sort((d,m)=>m.executionCount-d.executionCount).slice(0,10),a=i.filter((d)=>d.avgExecutionTime>1000).sort((d,m)=>m.avgExecutionTime-d.avgExecutionTime).slice(0,10),c=this.generateRecommendations(r,a),u={id:n,name:e.name,databaseIdentifier:e.databaseIdentifier,reportType:e.reportType,metrics:r,topQueries:s,slowQueries:a,recommendations:c,generatedAt:new Date};return this.reports.set(n,u),u}generateRecommendations(e,n){let r=[];if(e.avgCPU>70)r.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)r.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)r.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(n.length>0)r.push({type:"index",severity:"high",title:"Slow Queries Detected",description:`${n.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)r.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 r}analyzeQuery(e){let n=`analysis-${Date.now()}-${Math.random().toString(36).slice(2,9)}`,r=[{id:1,operation:"Seq Scan",table:"users",rows:1e4,cost:850.5,children:[]}],i=[];if(e.toLowerCase().includes("select *"))i.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"))i.push({type:"full_table_scan",severity:"critical",description:"Query has no WHERE clause and may scan entire table."});return{id:n,queryId:n,sql:e,executionPlan:r,bottlenecks:i,recommendations:["Add appropriate indexes on WHERE clause columns","Consider using EXPLAIN ANALYZE to get actual execution statistics","Review and optimize JOIN conditions"],estimatedCost:r[0].cost}}recommendIndex(e){let n=`index-rec-${Date.now()}-${this.recommendationCounter++}`,r=`idx_${e.tableName}_${e.columns.join("_")}`,i={id:n,tableName:e.tableName,columns:e.columns,reason:e.reason,estimatedImprovement:e.estimatedImprovement||50,estimatedSize:e.columns.length*10,createSQL:`CREATE INDEX ${r} ON ${e.tableName} (${e.columns.join(", ")});`};return this.indexRecommendations.set(n,i),i}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 rh=new Jl;class Xl{users=new Map;roles=new Map;audits=new Map;userCounter=0;roleCounter=0;auditCounter=0;createUser(e){let n=`db-user-${Date.now()}-${this.userCounter++}`,r={id:n,createdAt:new Date,...e};return this.users.set(n,r),r}createReadOnlyUser(e){let n=e.tables?e.tables.map((r)=>({database:e.database,table:r,privileges:["SELECT"]})):[{database:e.database,privileges:["SELECT"]}];return this.createUser({username:e.username,database:e.database,privileges:n,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:90})}createReadWriteUser(e){let n=e.tables?e.tables.map((r)=>({database:e.database,table:r,privileges:["SELECT","INSERT","UPDATE","DELETE"]})):[{database:e.database,privileges:["SELECT","INSERT","UPDATE","DELETE"]}];return this.createUser({username:e.username,database:e.database,privileges:n,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 n=e.tables.map((r)=>({database:e.database,table:r.name,privileges:r.privileges}));return this.createUser({username:e.username,database:e.database,privileges:n,passwordSecretArn:e.passwordSecretArn,rotationEnabled:!0,rotationDays:90})}createRole(e){let n=`role-${Date.now()}-${this.roleCounter++}`,r={id:n,users:[],...e};return this.roles.set(n,r),r}assignUserToRole(e,n){let r=this.users.get(e),i=this.roles.get(n);if(!r)throw Error(`User not found: ${e}`);if(!i)throw Error(`Role not found: ${n}`);i.users.push(e);for(let s of i.privileges){let a=r.privileges.find((c)=>c.database===s.database&&c.table===s.table);if(a)a.privileges=Array.from(new Set([...a.privileges,...s.privileges]));else r.privileges.push({...s})}}grantPrivileges(e,n){let r=this.users.get(e);if(!r)return{success:!1,message:"User not found"};for(let i of n){let s=r.privileges.find((a)=>a.database===i.database&&a.table===i.table);if(s)s.privileges=Array.from(new Set([...s.privileges,...i.privileges]));else r.privileges.push(i)}return this.auditAccess({username:r.username,action:"GRANT",database:n[0]?.database,table:n[0]?.table,success:!0}),{success:!0,message:"Privileges granted successfully"}}revokePrivileges(e,n){let r=this.users.get(e);if(!r)return{success:!1,message:"User not found"};for(let i of n){let s=r.privileges.findIndex((a)=>a.database===i.database&&a.table===i.table);if(s!==-1){let a=r.privileges[s];if(a.privileges=a.privileges.filter((c)=>!i.privileges.includes(c)),a.privileges.length===0)r.privileges.splice(s,1)}}return this.auditAccess({username:r.username,action:"REVOKE",database:n[0]?.database,table:n[0]?.table,success:!0}),{success:!0,message:"Privileges revoked successfully"}}rotatePassword(e){let n=this.users.get(e);if(!n)return{success:!1};let r=`arn:aws:secretsmanager:us-east-1:123456789012:secret:db-${n.username}-${Date.now()}`;return n.passwordSecretArn=r,n.lastRotated=new Date,console.log(`Password rotated for user: ${n.username}`),{success:!0,newSecretArn:r}}needsPasswordRotation(e){let n=this.users.get(e);if(!n||!n.rotationEnabled||!n.lastRotated||!n.rotationDays)return!1;return(Date.now()-n.lastRotated.getTime())/86400000>=n.rotationDays}auditAccess(e){let n=`audit-${Date.now()}-${this.auditCounter++}`,r={id:n,timestamp:new Date,...e};return this.audits.set(n,r),r}getUserAccessHistory(e,n=100){return Array.from(this.audits.values()).filter((r)=>r.username===e).sort((r,i)=>i.timestamp.getTime()-r.timestamp.getTime()).slice(0,n)}getFailedLoginAttempts(e,n=24){let r=Date.now()-n*60*60*1000;return Array.from(this.audits.values()).filter((i)=>i.username===e&&i.action==="LOGIN"&&!i.success&&i.timestamp.getTime()>r)}generateCreateUserSQL(e,n="postgres"){let r=[];if(n==="postgres"){r.push(`CREATE USER ${e.username} WITH PASSWORD '${e.passwordSecretArn}';`);for(let i of e.privileges)if(i.privileges.includes("ALL"))r.push(`GRANT ALL PRIVILEGES ON DATABASE ${i.database} TO ${e.username};`);else{let s=i.privileges.join(", ");if(i.table)r.push(`GRANT ${s} ON ${i.database}.${i.table} TO ${e.username};`);else r.push(`GRANT ${s} ON DATABASE ${i.database} TO ${e.username};`)}}else{r.push(`CREATE USER '${e.username}'@'%' IDENTIFIED BY '${e.passwordSecretArn}';`);for(let i of e.privileges){let s=i.privileges.includes("ALL")?"ALL PRIVILEGES":i.privileges.join(", "),a=i.table?`${i.database}.${i.table}`:`${i.database}.*`;r.push(`GRANT ${s} ON ${a} TO '${e.username}'@'%';`)}r.push("FLUSH PRIVILEGES;")}return r.join(`
|
|
3734
|
+
`)}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 nh=new Xl;class Ql{rotations=new Map;schedules=new Map;rotationCounter=0;scheduleCounter=0;createRotation(e){let n=`rotation-${Date.now()}-${this.rotationCounter++}`,r={id:n,...e};return this.rotations.set(n,r),r}enableRDSRotation(e){let n=this.createRotation({secretId:e.secretId,secretType:"rds_credentials",rotationEnabled:!0,rotationDays:e.rotationDays||30,rotationLambdaArn:this.generateRDSRotationLambdaArn(e.engine)});return n.nextRotation=new Date(Date.now()+n.rotationDays*24*60*60*1000),n}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 n=`schedule-${Date.now()}-${this.scheduleCounter++}`,r={id:n,...e};return this.schedules.set(n,r),r}async executeRotation(e){let n=this.rotations.get(e);if(!n)throw Error(`Rotation not found: ${e}`);console.log(`
|
|
3737
3735
|
Executing rotation for secret: ${n.secretId}`),console.log(`Secret type: ${n.secretType}`),console.log(`Rotation interval: ${n.rotationDays} days`);try{console.log(`
|
|
3738
3736
|
Rotation steps:`),console.log("1. Creating new secret version...");let r=`v${Date.now()}`;console.log("2. Testing new credentials..."),console.log("3. Updating application references..."),console.log("4. Marking previous version as deprecated...");let i=n.versionStages?.[0]||"v1";return console.log("5. Finalizing rotation..."),n.lastRotated=new Date,n.nextRotation=new Date(Date.now()+n.rotationDays*24*60*60*1000),console.log(`
|
|
3739
3737
|
✓ Rotation completed successfully`),console.log(` New version: ${r}`),console.log(` Next rotation: ${n.nextRotation.toISOString()}`),{success:!0,secretId:n.secretId,oldVersion:i,newVersion:r,rotatedAt:new Date}}catch(r){return console.error(`
|
|
3740
|
-
✗ Rotation failed:`,r),{success:!1,secretId:n.secretId,oldVersion:"unknown",newVersion:"unknown",rotatedAt:new Date,error:r instanceof Error?r.message:String(r)}}}needsRotation(e){let n=this.rotations.get(e);if(!n||!n.rotationEnabled)return!1;if(!n.lastRotated)return!0;return(Date.now()-n.lastRotated.getTime())/86400000>=n.rotationDays}getSecretsNeedingRotation(){return Array.from(this.rotations.values()).filter((e)=>this.needsRotation(e.id))}generateRDSRotationLambdaArn(e){let n={postgres:"SecretsManagerRDSPostgreSQLRotationSingleUser",mysql:"SecretsManagerRDSMySQLRotationSingleUser",sqlserver:"SecretsManagerRDSSQLServerRotationSingleUser",oracle:"SecretsManagerRDSOracleRotationSingleUser"};return`arn:aws:lambda:us-east-1:123456789012:function:${n[e]||n.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
|
|
3738
|
+
✗ Rotation failed:`,r),{success:!1,secretId:n.secretId,oldVersion:"unknown",newVersion:"unknown",rotatedAt:new Date,error:r instanceof Error?r.message:String(r)}}}needsRotation(e){let n=this.rotations.get(e);if(!n||!n.rotationEnabled)return!1;if(!n.lastRotated)return!0;return(Date.now()-n.lastRotated.getTime())/86400000>=n.rotationDays}getSecretsNeedingRotation(){return Array.from(this.rotations.values()).filter((e)=>this.needsRotation(e.id))}generateRDSRotationLambdaArn(e){let n={postgres:"SecretsManagerRDSPostgreSQLRotationSingleUser",mysql:"SecretsManagerRDSMySQLRotationSingleUser",sqlserver:"SecretsManagerRDSSQLServerRotationSingleUser",oracle:"SecretsManagerRDSOracleRotationSingleUser"};return`arn:aws:lambda:us-east-1:123456789012:function:${n[e]||n.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 ih=new Ql;class tc{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 n=`version-${Date.now()}-${this.versionCounter++}`,r={id:n,...e};return this.versions.set(n,r),this.auditAction({secretId:e.secretId,action:"CREATE",actor:"system",versionId:e.versionId,success:!0}),r}getVersionByStage(e,n){return Array.from(this.versions.values()).find((r)=>r.secretId===e&&r.versionStages.includes(n))}listVersions(e){return Array.from(this.versions.values()).filter((n)=>n.secretId===e).sort((n,r)=>r.createdAt.getTime()-n.createdAt.getTime())}deprecateVersion(e){let n=Array.from(this.versions.values()).find((r)=>r.versionId===e);if(n)n.deprecatedAt=new Date,n.versionStages=n.versionStages.filter((r)=>r!=="AWSCURRENT"),this.auditAction({secretId:n.secretId,action:"UPDATE",actor:"system",versionId:e,success:!0})}restoreVersion(e){let n=Array.from(this.versions.values()).find((r)=>r.versionId===e);if(n)Array.from(this.versions.values()).filter((r)=>r.secretId===n.secretId&&r.versionId!==e).forEach((r)=>{r.versionStages=r.versionStages.filter((i)=>i!=="AWSCURRENT")}),n.versionStages.push("AWSCURRENT"),n.deprecatedAt=void 0,this.auditAction({secretId:n.secretId,action:"RESTORE",actor:"system",versionId:e,success:!0})}auditAction(e){let n=`audit-${Date.now()}-${this.auditCounter++}`,r={id:n,timestamp:new Date,...e};return this.audits.set(n,r),r}getAuditTrail(e,n=100){return Array.from(this.audits.values()).filter((r)=>r.secretId===e).sort((r,i)=>i.timestamp.getTime()-r.timestamp.getTime()).slice(0,n)}getFailedAccesses(e,n=24){let r=Date.now()-n*60*60*1000;return Array.from(this.audits.values()).filter((i)=>i.secretId===e&&!i.success&&i.timestamp.getTime()>r)}registerExternalManager(e){let n=`ext-manager-${Date.now()}-${this.managerCounter++}`,r={id:n,...e};return this.externalManagers.set(n,r),r}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 n=`replication-${Date.now()}-${this.replicationCounter++}`,r={id:n,secretId:e.secretId,sourceRegion:e.sourceRegion,replicaRegions:e.replicaRegions,kmsKeyIds:e.kmsKeyIds,status:"replicating"};return this.replications.set(n,r),this.auditAction({secretId:e.secretId,action:"REPLICATE",actor:"system",success:!0}),setTimeout(()=>{r.status="completed"},100),r}createPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,secretId:e.secretId,policy:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:e.allowedPrincipals},Action:e.allowedActions,Resource:"*"}]}};return this.policies.set(n,r),r}createCrossAccountPolicy(e){let n=e.roleNames.map((r)=>`arn:aws:iam::${e.accountId}:role/${r}`);return this.createPolicy({secretId:e.secretId,allowedPrincipals:n,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((n)=>({Region:n}))}}}}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 Pp=new tc;class Yl{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 n=`cert-${Date.now()}-${this.certificateCounter++}`,r=`arn:aws:acm:us-east-1:123456789012:certificate/${n}`,i={id:n,arn:r,domainName:e.domainName,subjectAlternativeNames:e.subjectAlternativeNames,validationMethod:e.validationMethod||"DNS",status:"PENDING_VALIDATION"};return this.certificates.set(n,i),this.createValidation(i),i}requestWildcardCertificate(e){let n=[];if(e.includeApex)n.push(e.domainName.replace("*.",""));return this.requestCertificate({domainName:e.domainName,subjectAlternativeNames:n.length>0?n:void 0,validationMethod:"DNS"})}requestMultiDomainCertificate(e){return this.requestCertificate({domainName:e.primaryDomain,subjectAlternativeNames:e.additionalDomains,validationMethod:e.validationMethod||"DNS"})}createValidation(e){let n={domainName:e.domainName,validationMethod:e.validationMethod,validationStatus:"PENDING"};if(e.validationMethod==="DNS")n.resourceRecords=[{name:`_${Math.random().toString(36).slice(2)}.${e.domainName}`,type:"CNAME",value:`_${Math.random().toString(36).slice(2)}.acm-validations.aws.`}];else n.validationEmails=[`admin@${e.domainName}`,`administrator@${e.domainName}`,`hostmaster@${e.domainName}`];return this.validations.set(e.id,n),n}validateCertificate(e){let n=this.certificates.get(e),r=this.validations.get(e);if(!n||!r)return{success:!1,message:"Certificate or validation not found"};return r.validationStatus="SUCCESS",n.status="ISSUED",n.issuedAt=new Date,n.expiresAt=new Date(Date.now()+31536000000),n.renewalEligibility=!0,n.issuer="Amazon",{success:!0,message:"Certificate validated and issued successfully"}}enableAutoRenewal(e){let n=`renewal-${Date.now()}-${this.renewalCounter++}`,r={id:n,certificateArn:e.certificateArn,autoRenew:!0,renewBeforeDays:e.renewBeforeDays||30};return this.renewals.set(n,r),r}async renewCertificate(e){let n=this.renewals.get(e);if(!n)return{success:!1,message:"Renewal configuration not found"};let r=Array.from(this.certificates.values()).find((i)=>i.arn===n.certificateArn);if(!r)return{success:!1,message:"Certificate not found"};console.log(`
|
|
3741
3739
|
Renewing certificate: ${r.domainName}`),console.log(`Certificate ARN: ${r.arn}`);try{return console.log(`
|
|
3742
3740
|
1. Requesting new certificate...`),console.log("2. Validating domain ownership..."),console.log("3. Issuing renewed certificate..."),console.log("4. Updating resource associations..."),r.issuedAt=new Date,r.expiresAt=new Date(Date.now()+31536000000),n.lastRenewal=new Date,n.renewalStatus="success",n.nextRenewal=new Date(r.expiresAt.getTime()-n.renewBeforeDays*24*60*60*1000),console.log(`
|
|
3743
|
-
✓ Certificate renewed successfully`),console.log(` New expiration: ${r.expiresAt.toISOString()}`),console.log(` Next renewal: ${n.nextRenewal.toISOString()}`),{success:!0,message:"Certificate renewed successfully"}}catch(i){return n.renewalStatus="failed",this.createAlert({certificateArn:r.arn,alertType:"renewal_failed",severity:"critical",message:`Certificate renewal failed: ${i}`}),{success:!1,message:i instanceof Error?i.message:String(i)}}}createMonitor(e){let n=`monitor-${Date.now()}-${this.monitorCounter++}`,r={id:n,...e};return this.monitors.set(n,r),r}checkExpiration(){let e=[],n=Date.now();for(let r of this.certificates.values()){if(!r.expiresAt)continue;let i=(r.expiresAt.getTime()-n)/86400000;if(i<0)e.push(this.createAlert({certificateArn:r.arn,alertType:"expired",severity:"critical",message:`Certificate has expired for ${r.domainName}`}));else if(i<30)e.push(this.createAlert({certificateArn:r.arn,alertType:"expiring_soon",severity:i<7?"critical":"warning",message:`Certificate expiring in ${Math.floor(i)} days for ${r.domainName}`}))}return e}createAlert(e){let n=`alert-${Date.now()}-${this.alertCounter++}`,r={id:n,timestamp:new Date,acknowledged:!1,...e};return this.alerts.set(n,r),r}acknowledgeAlert(e){let n=this.alerts.get(e);if(n)n.acknowledged=!0}getCertificate(e){return this.certificates.get(e)}listCertificates(){return Array.from(this.certificates.values())}getExpiringCertificates(e=30){let n=Date.now()+e*24*60*60*1000;return Array.from(this.certificates.values()).filter((r)=>r.expiresAt&&r.expiresAt.getTime()<n)}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((n)=>n.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
|
|
3741
|
+
✓ Certificate renewed successfully`),console.log(` New expiration: ${r.expiresAt.toISOString()}`),console.log(` Next renewal: ${n.nextRenewal.toISOString()}`),{success:!0,message:"Certificate renewed successfully"}}catch(i){return n.renewalStatus="failed",this.createAlert({certificateArn:r.arn,alertType:"renewal_failed",severity:"critical",message:`Certificate renewal failed: ${i}`}),{success:!1,message:i instanceof Error?i.message:String(i)}}}createMonitor(e){let n=`monitor-${Date.now()}-${this.monitorCounter++}`,r={id:n,...e};return this.monitors.set(n,r),r}checkExpiration(){let e=[],n=Date.now();for(let r of this.certificates.values()){if(!r.expiresAt)continue;let i=(r.expiresAt.getTime()-n)/86400000;if(i<0)e.push(this.createAlert({certificateArn:r.arn,alertType:"expired",severity:"critical",message:`Certificate has expired for ${r.domainName}`}));else if(i<30)e.push(this.createAlert({certificateArn:r.arn,alertType:"expiring_soon",severity:i<7?"critical":"warning",message:`Certificate expiring in ${Math.floor(i)} days for ${r.domainName}`}))}return e}createAlert(e){let n=`alert-${Date.now()}-${this.alertCounter++}`,r={id:n,timestamp:new Date,acknowledged:!1,...e};return this.alerts.set(n,r),r}acknowledgeAlert(e){let n=this.alerts.get(e);if(n)n.acknowledged=!0}getCertificate(e){return this.certificates.get(e)}listCertificates(){return Array.from(this.certificates.values())}getExpiringCertificates(e=30){let n=Date.now()+e*24*60*60*1000;return Array.from(this.certificates.values()).filter((r)=>r.expiresAt&&r.expiresAt.getTime()<n)}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((n)=>n.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 oh=new Yl;class Zl{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 n=`scan-${Date.now()}-${this.scanCounter++}`,r={id:n,status:"queued",findings:[],...e};return this.scans.set(n,r),r}createContainerScan(e){return this.createScan({name:e.name,scanType:"container_image",target:{type:"ecr_image",identifier:e.imageUri,region:e.region||"us-east-1"}})}createLambdaScan(e){return this.createScan({name:e.name,scanType:"vulnerability",target:{type:"lambda",identifier:e.functionName,region:e.region||"us-east-1"}})}createSecretsDetectionScan(e){return this.createScan({name:e.name,scanType:"secrets_detection",target:{type:"repository",identifier:e.repositoryUrl}})}async executeScan(e){let n=this.scans.get(e);if(!n)throw Error(`Scan not found: ${e}`);console.log(`
|
|
3744
3742
|
Executing security scan: ${n.name}`),console.log(`Scan type: ${n.scanType}`),console.log(`Target: ${n.target.type} - ${n.target.identifier}`),n.status="running",n.startedAt=new Date;try{console.log(`
|
|
3745
3743
|
Scanning...`);let r=this.simulateFindings(n);return n.findings=r,n.status="completed",n.completedAt=new Date,n.summary={totalFindings:r.length,criticalCount:r.filter((i)=>i.severity==="CRITICAL").length,highCount:r.filter((i)=>i.severity==="HIGH").length,mediumCount:r.filter((i)=>i.severity==="MEDIUM").length,lowCount:r.filter((i)=>i.severity==="LOW").length,infoCount:r.filter((i)=>i.severity==="INFO").length,executionTime:n.completedAt.getTime()-n.startedAt.getTime()},console.log(`
|
|
3746
|
-
✓ Scan completed`),console.log(` Findings: ${n.summary.totalFindings}`),console.log(` Critical: ${n.summary.criticalCount}`),console.log(` High: ${n.summary.highCount}`),console.log(` Medium: ${n.summary.mediumCount}`),console.log(` Low: ${n.summary.lowCount}`),n}catch(r){throw n.status="failed",n.completedAt=new Date,r}}simulateFindings(e){let n=[],r=new Date;if(e.scanType==="container_image")n.push(this.createFinding({severity:"HIGH",title:"Vulnerable OpenSSL version detected",description:"OpenSSL 1.1.1k contains known vulnerabilities",cve:"CVE-2021-3711",cvss:7.5,affectedResource:e.target.identifier,remediation:"Update OpenSSL to version 1.1.1l or later",status:"OPEN",firstDetected:r,lastSeen:r})),n.push(this.createFinding({severity:"MEDIUM",title:"Outdated npm package: lodash",description:"lodash 4.17.19 has known security issues",cve:"CVE-2020-8203",cvss:5.3,affectedResource:e.target.identifier,remediation:"Update lodash to version 4.17.21 or later",status:"OPEN",firstDetected:r,lastSeen:r}));else if(e.scanType==="secrets_detection")n.push(this.createFinding({severity:"CRITICAL",title:"AWS Access Key exposed in code",description:"Hardcoded AWS access key found in source code",affectedResource:`${e.target.identifier}/src/config.ts:12`,remediation:"Remove hardcoded credentials and use AWS Secrets Manager",status:"OPEN",firstDetected:r,lastSeen:r}));return n}createFinding(e){let n=`finding-${Date.now()}-${this.findingCounter++}`,r={id:n,...e};return this.findings.set(n,r),r}suppressFinding(e,n){let r=this.findings.get(e);if(r){if(r.status="SUPPRESSED",console.log(`Finding suppressed: ${r.title}`),n)console.log(`Reason: ${n}`)}}resolveFinding(e){let n=this.findings.get(e);if(n)n.status="RESOLVED",console.log(`Finding resolved: ${n.title}`)}generateReport(e){let n=`report-${Date.now()}-${this.reportCounter++}`,r={id:n,scanId:e.scanId,reportType:e.reportType,format:e.format,generatedAt:new Date,s3Location:`s3://security-reports/${n}.${e.format}`};return this.reports.set(n,r),r}runComplianceCheck(e){let n=[];if(e.framework.includes("CIS"))n.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})),n.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 n}createComplianceCheck(e){let n=`check-${Date.now()}-${this.checkCounter++}`,r={id:n,...e};return this.complianceChecks.set(n,r),r}assessSecurityPosture(e){let n=`posture-${Date.now()}-${this.postureCounter++}`,r=Array.from(this.complianceChecks.values()),i=r.filter((d)=>d.status==="PASS").length,s=r.length,a=s>0?Math.round(i/s*100):0,c;if(a>=90)c="A";else if(a>=80)c="B";else if(a>=70)c="C";else if(a>=60)c="D";else c="F";let u={id:n,accountId:e.accountId,region:e.region,score:a,grade:c,assessedAt:new Date,strengths:["IAM password policy enforced","Multi-factor authentication enabled","CloudTrail logging enabled"],weaknesses:["Some S3 buckets are publicly accessible","Security groups allow unrestricted ingress","Outdated dependencies in Lambda functions"],recommendations:["Review and update S3 bucket policies","Implement least-privilege security group rules","Update Lambda runtime versions and dependencies","Enable GuardDuty for threat detection"]};return this.postures.set(n,u),u}getScan(e){return this.scans.get(e)}listScans(){return Array.from(this.scans.values())}getOpenFindings(e){return Array.from(this.findings.values()).filter((n)=>n.status==="OPEN"&&(!e||n.severity===e))}getComplianceChecksByStatus(e){return Array.from(this.complianceChecks.values()).filter((n)=>n.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
|
|
3744
|
+
✓ Scan completed`),console.log(` Findings: ${n.summary.totalFindings}`),console.log(` Critical: ${n.summary.criticalCount}`),console.log(` High: ${n.summary.highCount}`),console.log(` Medium: ${n.summary.mediumCount}`),console.log(` Low: ${n.summary.lowCount}`),n}catch(r){throw n.status="failed",n.completedAt=new Date,r}}simulateFindings(e){let n=[],r=new Date;if(e.scanType==="container_image")n.push(this.createFinding({severity:"HIGH",title:"Vulnerable OpenSSL version detected",description:"OpenSSL 1.1.1k contains known vulnerabilities",cve:"CVE-2021-3711",cvss:7.5,affectedResource:e.target.identifier,remediation:"Update OpenSSL to version 1.1.1l or later",status:"OPEN",firstDetected:r,lastSeen:r})),n.push(this.createFinding({severity:"MEDIUM",title:"Outdated npm package: lodash",description:"lodash 4.17.19 has known security issues",cve:"CVE-2020-8203",cvss:5.3,affectedResource:e.target.identifier,remediation:"Update lodash to version 4.17.21 or later",status:"OPEN",firstDetected:r,lastSeen:r}));else if(e.scanType==="secrets_detection")n.push(this.createFinding({severity:"CRITICAL",title:"AWS Access Key exposed in code",description:"Hardcoded AWS access key found in source code",affectedResource:`${e.target.identifier}/src/config.ts:12`,remediation:"Remove hardcoded credentials and use AWS Secrets Manager",status:"OPEN",firstDetected:r,lastSeen:r}));return n}createFinding(e){let n=`finding-${Date.now()}-${this.findingCounter++}`,r={id:n,...e};return this.findings.set(n,r),r}suppressFinding(e,n){let r=this.findings.get(e);if(r){if(r.status="SUPPRESSED",console.log(`Finding suppressed: ${r.title}`),n)console.log(`Reason: ${n}`)}}resolveFinding(e){let n=this.findings.get(e);if(n)n.status="RESOLVED",console.log(`Finding resolved: ${n.title}`)}generateReport(e){let n=`report-${Date.now()}-${this.reportCounter++}`,r={id:n,scanId:e.scanId,reportType:e.reportType,format:e.format,generatedAt:new Date,s3Location:`s3://security-reports/${n}.${e.format}`};return this.reports.set(n,r),r}runComplianceCheck(e){let n=[];if(e.framework.includes("CIS"))n.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})),n.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 n}createComplianceCheck(e){let n=`check-${Date.now()}-${this.checkCounter++}`,r={id:n,...e};return this.complianceChecks.set(n,r),r}assessSecurityPosture(e){let n=`posture-${Date.now()}-${this.postureCounter++}`,r=Array.from(this.complianceChecks.values()),i=r.filter((d)=>d.status==="PASS").length,s=r.length,a=s>0?Math.round(i/s*100):0,c;if(a>=90)c="A";else if(a>=80)c="B";else if(a>=70)c="C";else if(a>=60)c="D";else c="F";let u={id:n,accountId:e.accountId,region:e.region,score:a,grade:c,assessedAt:new Date,strengths:["IAM password policy enforced","Multi-factor authentication enabled","CloudTrail logging enabled"],weaknesses:["Some S3 buckets are publicly accessible","Security groups allow unrestricted ingress","Outdated dependencies in Lambda functions"],recommendations:["Review and update S3 bucket policies","Implement least-privilege security group rules","Update Lambda runtime versions and dependencies","Enable GuardDuty for threat detection"]};return this.postures.set(n,u),u}getScan(e){return this.scans.get(e)}listScans(){return Array.from(this.scans.values())}getOpenFindings(e){return Array.from(this.findings.values()).filter((n)=>n.status==="OPEN"&&(!e||n.severity===e))}getComplianceChecksByStatus(e){return Array.from(this.complianceChecks.values()).filter((n)=>n.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 sh=new Zl;class ed{configs=new Map;results=new Map;policies=new Map;configCounter=0;resultCounter=0;policyCounter=0;configureScan(e){let n=`scan-config-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.configs.set(n,r),r}configureTrivyScan(e){return this.configureScan({repository:e.repository,imageTag:e.imageTag,scanner:"trivy",scanOnPush:e.scanOnPush??!0,ignoreUnfixed:e.ignoreUnfixed??!1,failOnSeverity:"HIGH"})}configureSnykScan(e){return this.configureScan({repository:e.repository,imageTag:e.imageTag,scanner:"snyk",scanOnPush:e.scanOnPush??!0,failOnSeverity:"HIGH"})}configureECRScan(e){return this.configureScan({repository:e.repository,imageTag:"latest",scanner:"ecr",scanOnPush:e.scanOnPush??!0,failOnSeverity:"CRITICAL"})}async scanImage(e){let n=this.configs.get(e);if(!n)throw Error(`Scan config not found: ${e}`);let r=`${n.repository}:${n.imageTag}`;console.log(`
|
|
3747
3745
|
Scanning image: ${r}`),console.log(`Scanner: ${n.scanner}`);let i=`scan-result-${Date.now()}-${this.resultCounter++}`,s=this.simulateVulnerabilities(n),a={total:s.length,critical:s.filter((d)=>d.severity==="CRITICAL").length,high:s.filter((d)=>d.severity==="HIGH").length,medium:s.filter((d)=>d.severity==="MEDIUM").length,low:s.filter((d)=>d.severity==="LOW").length,unknown:s.filter((d)=>d.severity==="UNKNOWN").length},c=this.evaluateScanResult(n,a),u={id:i,imageUri:r,scannerType:n.scanner,scanDate:new Date,vulnerabilities:s,summary:a,passed:c};return this.results.set(i,u),console.log(`
|
|
3748
|
-
Scan Results:`),console.log(` Total vulnerabilities: ${a.total}`),console.log(` Critical: ${a.critical}`),console.log(` High: ${a.high}`),console.log(` Medium: ${a.medium}`),console.log(` Low: ${a.low}`),console.log(` Status: ${c?"✓ PASSED":"✗ FAILED"}`),u}simulateVulnerabilities(e){let n=[];if(e.scanner==="trivy"||e.scanner==="ecr")n.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}),n.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 n}evaluateScanResult(e,n){if(!e.failOnSeverity)return!0;switch(e.failOnSeverity){case"CRITICAL":return n.critical===0;case"HIGH":return n.critical===0&&n.high===0;case"MEDIUM":return n.critical===0&&n.high===0&&n.medium===0;case"LOW":return n.total===0;default:return!0}}createPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,...e};return this.policies.set(n,r),r}createStrictPolicy(e){return this.createPolicy({name:e,allowedSeverities:[],maxCritical:0,maxHigh:0,blockOnFailure:!0,exemptions:[]})}createPermissivePolicy(e){return this.createPolicy({name:e,allowedSeverities:["CRITICAL","HIGH","MEDIUM","LOW"],maxCritical:5,maxHigh:10,blockOnFailure:!1,exemptions:[]})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getResult(e){return this.results.get(e)}listResults(){return Array.from(this.results.values())}generateECRScanCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e.repository,ImageScanningConfiguration:{ScanOnPush:e.scanOnPush},ImageTagMutability:"IMMUTABLE",EncryptionConfiguration:{EncryptionType:"AES256"}}}}clear(){this.configs.clear(),this.results.clear(),this.policies.clear(),this.configCounter=0,this.resultCounter=0,this.policyCounter=0}}var
|
|
3746
|
+
Scan Results:`),console.log(` Total vulnerabilities: ${a.total}`),console.log(` Critical: ${a.critical}`),console.log(` High: ${a.high}`),console.log(` Medium: ${a.medium}`),console.log(` Low: ${a.low}`),console.log(` Status: ${c?"✓ PASSED":"✗ FAILED"}`),u}simulateVulnerabilities(e){let n=[];if(e.scanner==="trivy"||e.scanner==="ecr")n.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}),n.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 n}evaluateScanResult(e,n){if(!e.failOnSeverity)return!0;switch(e.failOnSeverity){case"CRITICAL":return n.critical===0;case"HIGH":return n.critical===0&&n.high===0;case"MEDIUM":return n.critical===0&&n.high===0&&n.medium===0;case"LOW":return n.total===0;default:return!0}}createPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,...e};return this.policies.set(n,r),r}createStrictPolicy(e){return this.createPolicy({name:e,allowedSeverities:[],maxCritical:0,maxHigh:0,blockOnFailure:!0,exemptions:[]})}createPermissivePolicy(e){return this.createPolicy({name:e,allowedSeverities:["CRITICAL","HIGH","MEDIUM","LOW"],maxCritical:5,maxHigh:10,blockOnFailure:!1,exemptions:[]})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getResult(e){return this.results.get(e)}listResults(){return Array.from(this.results.values())}generateECRScanCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e.repository,ImageScanningConfiguration:{ScanOnPush:e.scanOnPush},ImageTagMutability:"IMMUTABLE",EncryptionConfiguration:{EncryptionType:"AES256"}}}}clear(){this.configs.clear(),this.results.clear(),this.policies.clear(),this.configCounter=0,this.resultCounter=0,this.policyCounter=0}}var ah=new ed;class td{configs=new Map;multiStageConfigs=new Map;optimizations=new Map;analyses=new Map;configCounter=0;multiStageCounter=0;optimizationCounter=0;analysisCounter=0;createBuildConfig(e){let n=`build-config-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.configs.set(n,r),r}createOptimizedBuildConfig(e){let n={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:n,buildArgs:{BUILDKIT_INLINE_CACHE:"1"}})}createMultiStageConfig(e){let n=`multi-stage-${Date.now()}-${this.multiStageCounter++}`,r={id:n,...e};return this.multiStageConfigs.set(n,r),r}createNodeMultiStageBuild(e){let n=e.nodeVersion||"18-alpine";return this.createMultiStageConfig({name:e.name,targetStage:e.targetStage||"production",stages:[{name:"dependencies",baseImage:`node:${n}`,workdir:"/app",commands:["COPY package*.json ./","RUN npm ci --only=production"]},{name:"build",baseImage:`node:${n}`,workdir:"/app",commands:["COPY package*.json ./","RUN npm ci","COPY . .","RUN npm run build"]},{name:"production",baseImage:`node:${n}`,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 n=this.multiStageConfigs.get(e);if(!n)throw Error(`Multi-stage config not found: ${e}`);let r=[];for(let i of n.stages){if(r.push(`# Stage: ${i.name}`),r.push(`FROM ${i.baseImage} AS ${i.name}`),i.workdir)r.push(`WORKDIR ${i.workdir}`);if(i.env)for(let[s,a]of Object.entries(i.env))r.push(`ENV ${s}=${a}`);for(let s of i.commands)r.push(s);r.push("")}return r.join(`
|
|
3749
3747
|
`)}analyzeImage(e,n){let r=`analysis-${Date.now()}-${this.analysisCounter++}`,i=n.map((u)=>({...u,cacheable:this.isLayerCacheable(u.command)})),s=i.reduce((u,d)=>u+d.size,0),a=i.filter((u)=>!u.cacheable&&u.size>100).length,c={id:r,imageId:e,layers:i,totalSize:s,unnecessaryLayers:a};return this.analyses.set(r,c),c}isLayerCacheable(e){let n=["FROM","RUN","COPY","ADD","WORKDIR","ENV"],r=["CMD","ENTRYPOINT","LABEL"];for(let i of n)if(e.startsWith(i))return!0;for(let i of r)if(e.startsWith(i))return!1;return!1}generateOptimizations(e){let n=this.analyses.get(e);if(!n)throw Error(`Analysis not found: ${e}`);let r=`optimization-${Date.now()}-${this.optimizationCounter++}`,i=[],s=n.layers.filter((m)=>m.command.startsWith("RUN"));if(s.length>5)i.push({type:"layer_reduction",priority:"high",title:"Combine RUN commands",description:`${s.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 a=n.layers[0];if(a.command.includes("ubuntu")||a.command.includes("debian"))i.push({type:"base_image",priority:"medium",title:"Use Alpine base image",description:"Switch to Alpine Linux for smaller image size",example:"FROM node:18-alpine",impact:"Reduce image size by 50-70%"});let c=n.layers.filter((m)=>m.command.startsWith("COPY"));if(c.length>0&&c[0].index>3)i.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 ./
|
|
3750
3748
|
RUN npm install
|
|
3751
|
-
COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let u={sizeBefore:n.totalSize,sizeAfter:n.totalSize*0.6,timeBefore:300,timeAfter:120},d={id:r,name:`Optimization for ${n.imageId}`,recommendations:i,estimatedSavings:u};return this.optimizations.set(r,d),d}getBuildConfig(e){return this.configs.get(e)}listBuildConfigs(){return Array.from(this.configs.values())}getMultiStageConfig(e){return this.multiStageConfigs.get(e)}listMultiStageConfigs(){return Array.from(this.multiStageConfigs.values())}getOptimization(e){return this.optimizations.get(e)}listOptimizations(){return Array.from(this.optimizations.values())}clear(){this.configs.clear(),this.multiStageConfigs.clear(),this.optimizations.clear(),this.analyses.clear(),this.configCounter=0,this.multiStageCounter=0,this.optimizationCounter=0,this.analysisCounter=0}}var Jf=new Gl;class Ka{registries=new Map;credentials=new Map;registryCounter=0;credentialsCounter=0;createRegistry(e){let n=`registry-${Date.now()}-${this.registryCounter++}`,r={id:n,...e};return this.registries.set(n,r),r}createECRRepository(e){return this.createRegistry({name:e.name,registryType:"ecr",repositoryUri:`123456789012.dkr.ecr.${e.region||"us-east-1"}.amazonaws.com/${e.name}`,region:e.region||"us-east-1",encryption:{encryptionType:e.encryption||"AES256",kmsKeyId:e.kmsKeyId},scanning:{scanOnPush:e.scanOnPush??!0}})}createManagedRepository(e){let n=this.createECRRepository({name:e.name,region:e.region,scanOnPush:!0,encryption:"KMS"});return n.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"}}]},n}enableReplication(e,n){let r=this.registries.get(e);if(!r)throw Error(`Registry not found: ${e}`);return r.replication={enabled:!0,destinations:n},r}createCredentials(e){let n=`creds-${Date.now()}-${this.credentialsCounter++}`,r={id:n,...e};return this.credentials.set(n,r),r}getRegistry(e){return this.registries.get(e)}listRegistries(){return Array.from(this.registries.values())}generateECRRepositoryCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e.name,ImageScanningConfiguration:{ScanOnPush:e.scanning?.scanOnPush??!1},EncryptionConfiguration:{EncryptionType:e.encryption?.encryptionType||"AES256",...e.encryption?.kmsKeyId&&{KmsKey:e.encryption.kmsKeyId}},ImageTagMutability:"MUTABLE",...e.lifecycle&&{LifecyclePolicy:{LifecyclePolicyText:JSON.stringify({rules:e.lifecycle.rules})}}}}}generateReplicationConfigCF(e){return{Type:"AWS::ECR::ReplicationConfiguration",Properties:{ReplicationConfiguration:{Rules:e.destinations.map((n)=>({Destinations:[{Region:n.region,...n.registryId&&{RegistryId:n.registryId}}]}))}}}}clear(){this.registries.clear(),this.credentials.clear(),this.registryCounter=0,this.credentialsCounter=0}}var yp=new Ka;class Ja{meshes=new Map;virtualNodes=new Map;virtualRouters=new Map;virtualGateways=new Map;meshCounter=0;nodeCounter=0;routerCounter=0;gatewayCounter=0;createMesh(e){let n=`mesh-${Date.now()}-${this.meshCounter++}`,r={id:n,...e};return this.meshes.set(n,r),r}createAppMesh(e){return this.createMesh({name:e.name,meshType:"app_mesh",services:e.services,virtualNodes:[],virtualRouters:[],virtualGateways:[]})}createVirtualNode(e){let n=`vnode-${Date.now()}-${this.nodeCounter++}`,r={id:n,...e};return this.virtualNodes.set(n,r),r}createHTTPVirtualNode(e){return this.createVirtualNode({name:e.name,serviceName:e.serviceName,listeners:[{port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3},timeout:{perRequest:15000,idle:300000}}],serviceDiscovery:{type:"aws_cloud_map",namespace:e.namespace,serviceName:e.serviceName}})}createVirtualRouter(e){let n=`vrouter-${Date.now()}-${this.routerCounter++}`,r={id:n,...e};return this.virtualRouters.set(n,r),r}createCanaryRoute(e){return this.createVirtualRouter({name:e.name,listeners:[{port:e.port,protocol:e.protocol}],routes:[{name:"canary-route",match:{prefix:"/"},action:{weightedTargets:[{virtualNode:e.stableTarget,weight:100-e.canaryWeight},{virtualNode:e.canaryTarget,weight:e.canaryWeight}]},retryPolicy:{maxRetries:3,perRetryTimeout:5000,httpRetryEvents:["server-error","gateway-error"],tcpRetryEvents:["connection-error"]}}]})}createVirtualGateway(e){let n=`vgateway-${Date.now()}-${this.gatewayCounter++}`,r={id:n,...e};return this.virtualGateways.set(n,r),r}createIngressGateway(e){let n={port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3}};if(e.enableTLS&&e.certificateArn)n.tls={mode:"STRICT",certificate:{acm:e.certificateArn}};return this.createVirtualGateway({name:e.name,listeners:[n],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,n){return{Type:"AWS::AppMesh::VirtualNode",Properties:{MeshName:n,VirtualNodeName:e.name,Spec:{Listeners:e.listeners.map((r)=>({PortMapping:{Port:r.port,Protocol:r.protocol},...r.healthCheck&&{HealthCheck:{Protocol:r.healthCheck.protocol,...r.healthCheck.path&&{Path:r.healthCheck.path},IntervalMillis:r.healthCheck.interval*1000,TimeoutMillis:r.healthCheck.timeout*1000,HealthyThreshold:r.healthCheck.healthyThreshold,UnhealthyThreshold:r.healthCheck.unhealthyThreshold}}})),ServiceDiscovery:{AWSCloudMap:{NamespaceName:e.serviceDiscovery.namespace,ServiceName:e.serviceDiscovery.serviceName}}}}}}generateVirtualRouterCF(e,n){return{Type:"AWS::AppMesh::VirtualRouter",Properties:{MeshName:n,VirtualRouterName:e.name,Spec:{Listeners:e.listeners.map((r)=>({PortMapping:{Port:r.port,Protocol:r.protocol}}))}}}}clear(){this.meshes.clear(),this.virtualNodes.clear(),this.virtualRouters.clear(),this.virtualGateways.clear(),this.meshCounter=0,this.nodeCounter=0,this.routerCounter=0,this.gatewayCounter=0}}var bp=new Ja;class ql{layers=new Map;versions=new Map;permissions=new Map;layerCounter=0;versionCounter=0;permissionCounter=0;createLayer(e){let n=`layer-${Date.now()}-${this.layerCounter++}`,r=1,i={id:n,layerArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:1`,version:1,...e};return this.layers.set(n,i),i}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 n=this.layers.get(e);if(!n)throw Error(`Layer not found: ${e}`);let r=`version-${Date.now()}-${this.versionCounter++}`,i=n.version+1,s={id:r,layerName:n.layerName,version:i,createdAt:new Date,compatibleRuntimes:n.compatibleRuntimes,size:n.size,codeHash:this.generateHash()};return this.versions.set(r,s),n.version=i,n.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${n.layerName}:${i}`,s}addPermission(e){let n=`permission-${Date.now()}-${this.permissionCounter++}`,r={id:n,layerName:e.layerName,version:e.version,principal:e.principal,action:"lambda:GetLayerVersion",organizationId:e.organizationId};return this.permissions.set(n,r),r}generateHash(){return Math.random().toString(36).substring(2,15)}getLayer(e){return this.layers.get(e)}listLayers(){return Array.from(this.layers.values())}getLayerVersions(e){return Array.from(this.versions.values()).filter((n)=>n.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 Xf=new ql;class Wl{versions=new Map;aliases=new Map;deployments=new Map;versionCounter=0;aliasCounter=0;deploymentCounter=0;publishVersion(e){let n=`version-${Date.now()}-${this.versionCounter++}`,r=this.getNextVersionNumber(e.functionName),i={id:n,functionName:e.functionName,version:r.toString(),functionArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${r}`,codeHash:this.generateHash(),description:e.description,runtime:e.runtime,memorySize:e.memorySize,timeout:e.timeout,publishedAt:new Date};return this.versions.set(n,i),i}getNextVersionNumber(e){let n=Array.from(this.versions.values()).filter((r)=>r.functionName===e).map((r)=>parseInt(r.version));return n.length>0?Math.max(...n)+1:1}createAlias(e){let n=`alias-${Date.now()}-${this.aliasCounter++}`,r={id:n,aliasArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${e.aliasName}`,revisionId:this.generateHash(),...e};return this.aliases.set(n,r),r}createProductionAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"production",functionVersion:e.version,description:"Production alias"})}createStagingAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"staging",functionVersion:e.version,description:"Staging alias"})}updateAlias(e,n){let r=this.aliases.get(e);if(!r)throw Error(`Alias not found: ${e}`);return r.functionVersion=n,r.revisionId=this.generateHash(),r}configureWeightedRouting(e,n){let r=this.aliases.get(e);if(!r)throw Error(`Alias not found: ${e}`);return r.routingConfig={additionalVersionWeights:n},r}createCanaryDeployment(e){let n=`deployment-${Date.now()}-${this.deploymentCounter++}`,r=Array.from(this.aliases.values()).find((s)=>s.functionName===e.functionName&&s.aliasName===e.aliasName);if(!r)r=this.createAlias({functionName:e.functionName,aliasName:e.aliasName,functionVersion:e.fromVersion});this.configureWeightedRouting(r.id,{[e.toVersion]:e.canaryWeight});let i={id:n,functionName:e.functionName,fromVersion:e.fromVersion,toVersion:e.toVersion,aliasName:e.aliasName,strategy:"canary",status:"in_progress",startedAt:new Date};return this.deployments.set(n,i),i}completeDeployment(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r=Array.from(this.aliases.values()).find((i)=>i.functionName===n.functionName&&i.aliasName===n.aliasName);if(r)r.functionVersion=n.toVersion,r.routingConfig=void 0;return n.status="completed",n.completedAt=new Date,n}rollbackDeployment(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r=Array.from(this.aliases.values()).find((i)=>i.functionName===n.functionName&&i.aliasName===n.aliasName);if(r)r.functionVersion=n.fromVersion,r.routingConfig=void 0;return n.status="failed",n.completedAt=new Date,n}generateHash(){return Math.random().toString(36).substring(2,15)}getVersion(e){return this.versions.get(e)}listVersions(e){let n=Array.from(this.versions.values());return e?n.filter((r)=>r.functionName===e):n}getAlias(e){return this.aliases.get(e)}listAliases(e){let n=Array.from(this.aliases.values());return e?n.filter((r)=>r.functionName===e):n}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(([n,r])=>({FunctionVersion:n,FunctionWeight:r}))}}}}}clear(){this.versions.clear(),this.aliases.clear(),this.deployments.clear(),this.versionCounter=0,this.aliasCounter=0,this.deploymentCounter=0}}var Qf=new Wl;class Kl{configs=new Map;provisionedConfigs=new Map;schedules=new Map;autoScalingConfigs=new Map;configCounter=0;provisionedCounter=0;scheduleCounter=0;autoScalingCounter=0;setReservedConcurrency(e){let n=`concurrency-${Date.now()}-${this.configCounter++}`,r={id:n,functionName:e.functionName,reservedConcurrency:e.reservedConcurrency};return this.configs.set(n,r),r}setProvisionedConcurrency(e){let n=`provisioned-${Date.now()}-${this.provisionedCounter++}`,r={id:n,functionName:e.functionName,qualifier:e.qualifier,provisionedConcurrentExecutions:e.provisionedConcurrentExecutions,status:"pending",lastModified:new Date};return this.provisionedConfigs.set(n,r),setTimeout(()=>{r.status="ready",r.allocatedConcurrency=e.provisionedConcurrentExecutions,r.availableConcurrency=e.provisionedConcurrentExecutions},100),r}configureWarmPool(e){return this.setProvisionedConcurrency({functionName:e.functionName,qualifier:e.alias,provisionedConcurrentExecutions:e.minInstances})}createSchedule(e){let n=`schedule-${Date.now()}-${this.scheduleCounter++}`,r={id:n,...e};return this.schedules.set(n,r),r}createBusinessHoursSchedule(e){return this.createSchedule({name:`${e.functionName}-business-hours`,functionName:e.functionName,qualifier:e.qualifier,schedule:[{name:"business-hours",cronExpression:"0 8 * * MON-FRI",targetConcurrency:e.businessHoursConcurrency},{name:"off-hours",cronExpression:"0 18 * * MON-FRI",targetConcurrency:e.offHoursConcurrency},{name:"weekend",cronExpression:"0 0 * * SAT",targetConcurrency:e.offHoursConcurrency}]})}configureAutoScaling(e){let n=`autoscaling-${Date.now()}-${this.autoScalingCounter++}`,r={id:n,...e};return this.autoScalingConfigs.set(n,r),r}configurePredictiveScaling(e){return this.configureAutoScaling({functionName:e.functionName,qualifier:e.qualifier,minCapacity:e.baselineCapacity,maxCapacity:e.peakCapacity,targetUtilization:0.7,scaleInCooldown:300,scaleOutCooldown:60})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getProvisionedConfig(e){return this.provisionedConfigs.get(e)}listProvisionedConfigs(){return Array.from(this.provisionedConfigs.values())}generateReservedConcurrencyCF(e){return{Type:"AWS::Lambda::Function",Properties:{FunctionName:e.functionName,ReservedConcurrentExecutions:e.reservedConcurrency}}}generateProvisionedConcurrencyCF(e){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.functionName,Name:e.qualifier,ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:e.provisionedConcurrentExecutions}}}}generateAutoScalingTargetCF(e){return{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{ServiceNamespace:"lambda",ResourceId:`function:${e.functionName}:${e.qualifier}`,ScalableDimension:"lambda:function:ProvisionedConcurrentExecutions",MinCapacity:e.minCapacity,MaxCapacity:e.maxCapacity}}}generateAutoScalingPolicyCF(e){return{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e.functionName}-autoscaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:`${e.functionName}AutoScalingTarget`},TargetTrackingScalingPolicyConfiguration:{TargetValue:e.targetUtilization*100,PredefinedMetricSpecification:{PredefinedMetricType:"LambdaProvisionedConcurrencyUtilization"},ScaleInCooldown:e.scaleInCooldown||300,ScaleOutCooldown:e.scaleOutCooldown||60}}}}clear(){this.configs.clear(),this.provisionedConfigs.clear(),this.schedules.clear(),this.autoScalingConfigs.clear(),this.configCounter=0,this.provisionedCounter=0,this.scheduleCounter=0,this.autoScalingCounter=0}}var Yf=new Kl;class Jl{destinations=new Map;records=new Map;eventBridgeDestinations=new Map;destinationCounter=0;recordCounter=0;eventBridgeCounter=0;configureDestinations(e){let n=`destination-${Date.now()}-${this.destinationCounter++}`,r={id:n,...e};return this.destinations.set(n,r),r}configureSQSDestination(e){let n={type:"sqs",arn:e.queueArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureSNSDestination(e){let n={type:"sns",arn:e.topicArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureEventBridgeDestination(e){let n={type:"eventbridge",arn:e.eventBusArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureLambdaDestination(e){let n={type:"lambda",arn:e.destinationFunctionArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n: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 n=`eventbridge-${Date.now()}-${this.eventBridgeCounter++}`,r={id:n,functionName:e.functionName,eventBusArn:e.eventBusArn,detailType:e.detailType||"Lambda Function Invocation Result",source:e.source||`lambda.${e.functionName}`};return this.eventBridgeDestinations.set(n,r),r}sendToDestination(e){let n=Array.from(this.destinations.values()).find((a)=>a.functionName===e.functionName);if(!n)return null;let r=e.status==="success"?n.successDestination:n.failureDestination;if(!r)return null;let i=`record-${Date.now()}-${this.recordCounter++}`,s={id:i,timestamp:new Date,functionName:e.functionName,requestId:e.requestId,status:e.status,destinationType:r.type,destinationArn:r.arn,payload:e.payload,error:e.error};return this.records.set(i,s),s}getDestination(e){return this.destinations.get(e)}listDestinations(e){let n=Array.from(this.destinations.values());return e?n.filter((r)=>r.functionName===e):n}getDestinationRecords(e){let n=Array.from(this.records.values());return e?n.filter((r)=>r.functionName===e):n}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 Zf=new Jl;class Xl{vpcConfigs=new Map;endpoints=new Map;networkInterfaces=new Map;connectivity=new Map;configCounter=0;endpointCounter=0;eniCounter=0;connectivityCounter=0;configureVPC(e){let n=`vpc-config-${Date.now()}-${this.configCounter++}`,r={id:n,...e};this.vpcConfigs.set(n,r);for(let i of e.subnetIds)this.createNetworkInterface({functionName:e.functionName,subnetId:i});return r}configurePrivateVPC(e){return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.privateSubnetIds,securityGroupIds:[e.securityGroupId],ipv6Allowed:!1})}configureMultiAZVPC(e){if(e.subnetIds.length<2)throw Error("Multi-AZ configuration requires at least 2 subnets");return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds})}createVPCEndpoint(e){let n=`endpoint-${Date.now()}-${this.endpointCounter++}`,r={id:n,...e};return this.endpoints.set(n,r),r}createS3Endpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.s3",endpointType:"Gateway",privateDnsEnabled:!1})}createDynamoDBEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.dynamodb",endpointType:"Gateway",privateDnsEnabled:!1})}createSecretsManagerEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.secretsmanager",endpointType:"Interface",subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds,privateDnsEnabled:!0})}createNetworkInterface(e){let n=`eni-${Date.now()}-${this.eniCounter++}`,r={id:n,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(n,r),setTimeout(()=>{r.status="available"},100),r}analyzeConnectivity(e){let n=`connectivity-${Date.now()}-${this.connectivityCounter++}`,r=Array.from(this.vpcConfigs.values()).find((d)=>d.functionName===e.functionName),i=Array.from(this.endpoints.values()).filter((d)=>d.vpcId===r?.vpcId).map((d)=>d.serviceName),s=[],a=e.hasNATGateway??!1,c=e.hasInternetGateway??!1;if(!a&&!c)s.push("Add NAT Gateway for internet access");if(!i.includes("com.amazonaws.us-east-1.s3"))s.push("Add S3 VPC endpoint to reduce NAT costs");if(!i.includes("com.amazonaws.us-east-1.dynamodb"))s.push("Add DynamoDB VPC endpoint for private access");let u={id:n,functionName:e.functionName,hasInternetAccess:a||c,hasNATGateway:a,hasVPCEndpoints:i.length>0,endpoints:i,recommendations:s};return this.connectivity.set(n,u),u}getVPCConfig(e){return this.vpcConfigs.get(e)}listVPCConfigs(e){let n=Array.from(this.vpcConfigs.values());return e?n.filter((r)=>r.functionName===e):n}getNetworkInterfaces(e){return Array.from(this.networkInterfaces.values()).filter((n)=>n.functionName===e)}listVPCEndpoints(e){let n=Array.from(this.endpoints.values());return e?n.filter((r)=>r.vpcId===e):n}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((n)=>({IpProtocol:n.protocol,FromPort:n.fromPort,ToPort:n.toPort,...n.cidrIp&&{CidrIp:n.cidrIp},...n.sourceSecurityGroupId&&{SourceSecurityGroupId:n.sourceSecurityGroupId}}))},...e.egressRules&&{SecurityGroupEgress:e.egressRules.map((n)=>({IpProtocol:n.protocol,FromPort:n.fromPort,ToPort:n.toPort,CidrIp:n.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 eh=new Xl;class Ql{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(e){let n=`dlq-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.dlqConfigs.set(n,r),r}configureSQSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.queueArn,targetType:"sqs",maxReceiveCount:e.maxReceiveCount||3,retentionPeriod:e.retentionPeriod||1209600})}configureSNSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.topicArn,targetType:"sns"})}configureDLQWithAlarm(e){let n=this.configureSQSDLQ({functionName:e.functionName,queueArn:e.queueArn});return this.createDLQAlarm({dlqConfigId:n.id,alarmName:`${e.functionName}-dlq-alarm`,threshold:e.alarmThreshold,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0}),n}sendToDLQ(e){let n=`message-${Date.now()}-${this.messageCounter++}`,r={id:n,timestamp:new Date,...e};return this.messages.set(n,r),r}createDLQAlarm(e){let n=`alarm-${Date.now()}-${this.alarmCounter++}`,r={id:n,...e};return this.alarms.set(n,r),r}createAgeAlarm(e){let n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:e.dlqConfigId,alarmName:`${n.functionName}-dlq-age-alarm`,threshold:e.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0})}async reprocessMessage(e){let n=this.messages.get(e);if(!n)throw Error(`Message not found: ${e}`);let r=Array.from(this.dlqConfigs.values()).find((a)=>a.functionName===n.functionName);if(!r)throw Error(`DLQ config not found for function: ${n.functionName}`);let i=`reprocess-${Date.now()}-${this.reprocessCounter++}`,s={id:i,dlqConfigId:r.id,messageId:e,status:"pending",startedAt:new Date};return this.reprocessing.set(i,s),setTimeout(()=>{s.status="processing",setTimeout(()=>{let a=Math.random()>0.3;if(s.status=a?"success":"failed",s.completedAt=new Date,!a)s.error="Reprocessing failed - same error occurred";else this.messages.delete(e)},100)},50),s}async batchReprocess(e){let n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);let i=Array.from(this.messages.values()).filter((s)=>s.functionName===n.functionName).slice(0,e.maxMessages||10).map((s)=>this.reprocessMessage(s.id));return Promise.all(i)}getDLQStats(e){let n=this.dlqConfigs.get(e);if(!n)throw Error(`DLQ config not found: ${e}`);let r=Array.from(this.messages.values()).filter((c)=>c.functionName===n.functionName),i={},s=0;for(let c of r)i[c.errorType]=(i[c.errorType]||0)+1,s+=c.attemptCount;let a=r.map((c)=>c.timestamp);return{totalMessages:r.length,oldestMessage:a.length>0?new Date(Math.min(...a.map((c)=>c.getTime()))):void 0,newestMessage:a.length>0?new Date(Math.max(...a.map((c)=>c.getTime()))):void 0,averageAttempts:r.length>0?s/r.length:0,errorTypes:i}}getDLQConfig(e){return this.dlqConfigs.get(e)}listDLQConfigs(){return Array.from(this.dlqConfigs.values())}getDLQMessages(e){let n=this.dlqConfigs.get(e);if(!n)return[];return Array.from(this.messages.values()).filter((r)=>r.functionName===n.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 n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`DLQ alarm for ${n.functionName}`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:e.evaluationPeriods,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:n.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 th=new Ql;class Xa{policies=new Map;healthChecks=new Map;trafficPolicies=new Map;policyCounter=0;healthCheckCounter=0;trafficPolicyCounter=0;createWeightedPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"weighted",...e};return this.policies.set(n,r),r}createLatencyPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"latency",...e};return this.policies.set(n,r),r}createFailoverPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"failover",...e};return this.policies.set(n,r),r}createGeolocationPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"geolocation",...e};return this.policies.set(n,r),r}createGeoproximityPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"geoproximity",...e};return this.policies.set(n,r),r}createHTTPHealthCheck(e){let n=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:n,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(n,r),setTimeout(()=>{r.healthCheckStatus=Math.random()>0.2?"Healthy":"Unhealthy"},100),r}createTCPHealthCheck(e){let n=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:n,type:"tcp",fullyQualifiedDomainName:e.ipAddress,requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(n,r),setTimeout(()=>{r.healthCheckStatus=Math.random()>0.1?"Healthy":"Unhealthy"},100),r}createCalculatedHealthCheck(e){let n=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:n,type:"calculated",requestInterval:30,failureThreshold:0,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(n,r),setTimeout(()=>{let s=e.childHealthChecks.filter((a)=>this.healthChecks.get(a)?.healthCheckStatus==="Healthy").length;r.healthCheckStatus=s>=e.healthThreshold?"Healthy":"Unhealthy"},150),r}createTrafficPolicy(e){let n=`traffic-policy-${Date.now()}-${this.trafficPolicyCounter++}`,r={id:n,version:1,...e};return this.trafficPolicies.set(n,r),r}createFailoverTrafficPolicy(e){return this.createTrafficPolicy({name:e.name,document:{recordType:e.recordType||"A",startRule:"failover",endpoints:{primary:{type:"value",value:e.primaryEndpoint},secondary:{type:"value",value:e.secondaryEndpoint}},rules:{failover:{ruleType:"failover",primary:"primary",secondary:"secondary"}}}})}createGeoproximityTrafficPolicy(e){let n={},r=[];return e.locations.forEach((i,s)=>{let a=`endpoint${s}`;n[a]={type:"value",value:i.endpoint},r.push({endpointReference:a,region:i.region,latitude:i.latitude,longitude:i.longitude,bias:i.bias})}),this.createTrafficPolicy({name:e.name,document:{recordType:"A",startRule:"geoproximity",endpoints:n,rules:{geoproximity:{ruleType:"geoproximity",locations:r}}}})}getPolicy(e){return this.policies.get(e)}listPolicies(){return Array.from(this.policies.values())}getHealthCheck(e){return this.healthChecks.get(e)}listHealthChecks(){return Array.from(this.healthChecks.values())}getHealthCheckStatus(e){return this.healthChecks.get(e)?.healthCheckStatus||"Unknown"}generateHealthCheckCF(e){let n={Type:"AWS::Route53::HealthCheck",Properties:{HealthCheckConfig:{Type:e.type.toUpperCase(),RequestInterval:e.requestInterval,FailureThreshold:e.failureThreshold,...e.measureLatency&&{MeasureLatency:!0}},HealthCheckTags:[{Key:"Name",Value:e.name}]}};if(e.type==="calculated"){let r=e;n.Properties.HealthCheckConfig.ChildHealthChecks=r.childHealthChecks,n.Properties.HealthCheckConfig.HealthThreshold=r.healthThreshold}else{if(e.ipAddress)n.Properties.HealthCheckConfig.IPAddress=e.ipAddress;if(e.fullyQualifiedDomainName)n.Properties.HealthCheckConfig.FullyQualifiedDomainName=e.fullyQualifiedDomainName;if(e.port)n.Properties.HealthCheckConfig.Port=e.port;if(e.resourcePath)n.Properties.HealthCheckConfig.ResourcePath=e.resourcePath;if(e.enableSNI)n.Properties.HealthCheckConfig.EnableSNI=!0}return n}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 Sp=new Xa;class Yl{configs=new Map;ksks=new Map;validations=new Map;configCounter=0;kskCounter=0;validationCounter=0;enableDNSSEC(e){let n=`dnssec-${Date.now()}-${this.configCounter++}`,r={id:n,hostedZoneId:e.hostedZoneId,status:"SIGNING",signingStatus:"Initializing DNSSEC signing"};if(this.configs.set(n,r),e.kmsKeyArn)this.createKSK({name:`ksk-${e.hostedZoneId}`,hostedZoneId:e.hostedZoneId,kmsKeyArn:e.kmsKeyArn});return setTimeout(()=>{r.status="SIGNED",r.signingStatus="DNSSEC signing complete"},100),r}disableDNSSEC(e){let n=this.configs.get(e);if(!n)throw Error(`DNSSEC config not found: ${e}`);return n.status="DELETING",n.signingStatus="Removing DNSSEC signing",setTimeout(()=>{n.status="NOT_SIGNING",n.signingStatus="DNSSEC signing removed"},100),n}createKSK(e){let n=`ksk-${Date.now()}-${this.kskCounter++}`,r={id:n,status:"ACTIVE",flag:257,keyManagementServiceArn:e.kmsKeyArn,digestAlgorithm:2,keyTag:Math.floor(Math.random()*65535),publicKey:this.generatePublicKey(),...e};r.dnskeyRecord=`${r.flag} 3 8 ${r.publicKey}`;let i=this.generateDigest(r.dnskeyRecord);return r.digestValue=i,r.dsRecord=`${r.keyTag} 8 ${r.digestAlgorithm} ${i}`,this.ksks.set(n,r),r}deactivateKSK(e){let n=this.ksks.get(e);if(!n)throw Error(`KSK not found: ${e}`);return n.status="INACTIVE",n}validateDNSSEC(e){let n=`validation-${Date.now()}-${this.validationCounter++}`,r=e.checkDNSKEY!==!1?Math.random()>0.1:!1,i=e.checkRRSIG!==!1?Math.random()>0.1:!1,s=r&&i,a=[];if(!r)a.push("DNSKEY record not found");if(!i)a.push("RRSIG record not found");let c;if(!r&&!i)c="INSECURE";else if(r&&i&&s)c="VALID";else if(r||i)c="BOGUS",a.push("Invalid signature or incomplete DNSSEC chain");else c="INVALID";let u={id:n,domain:e.domain,validationStatus:c,dnskeyPresent:r,rrsigPresent:i,validSignature:s,errors:a};return this.validations.set(n,u),u}getDNSSECConfig(e){return this.configs.get(e)}listDNSSECConfigs(){return Array.from(this.configs.values())}getKSK(e){return this.ksks.get(e)}listKSKs(e){let n=Array.from(this.ksks.values());return e?n.filter((r)=>r.hostedZoneId===e):n}getDSRecord(e){let n=this.ksks.get(e);if(!n||!n.dsRecord)throw Error("DS record not available");return n.dsRecord}generatePublicKey(){let n="";for(let r=0;r<256;r++)n+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return n}generateDigest(e){let r="";for(let i=0;i<64;i++)r+="0123456789ABCDEF".charAt(Math.floor(Math.random()*16));return r}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 rh=new Yl;class Zl{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 n=`endpoint-${Date.now()}-${this.endpointCounter++}`,r={id:n,status:"CREATING",...e};return this.endpoints.set(n,r),setTimeout(()=>{r.status="OPERATIONAL",r.ipAddresses.forEach((i)=>{if(!i.ip)i.ip=`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`})},100),r}createInboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"INBOUND",ipAddresses:e.subnetIds.map((n)=>({subnetId:n})),securityGroupIds:e.securityGroupIds})}createOutboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"OUTBOUND",ipAddresses:e.subnetIds.map((n)=>({subnetId:n})),securityGroupIds:e.securityGroupIds})}createResolverRule(e){let n=`rule-${Date.now()}-${this.ruleCounter++}`,r={id:n,status:"CREATING",...e};return this.rules.set(n,r),setTimeout(()=>{r.status="COMPLETE"},100),r}createForwardRule(e){return this.createResolverRule({name:e.name,ruleType:"FORWARD",domainName:e.domainName,targetIps:e.targetIps,resolverEndpointId:e.resolverEndpointId})}createSystemRule(e){return this.createResolverRule({name:e.name,ruleType:"SYSTEM",domainName:e.domainName})}createFirewallDomainList(e){let n=`domain-list-${Date.now()}-${this.domainListCounter++}`,r={id:n,status:"CREATING",...e};return this.domainLists.set(n,r),setTimeout(()=>{r.status="COMPLETE"},100),r}createFirewallRuleGroup(e){let n=`rule-group-${Date.now()}-${this.ruleGroupCounter++}`,r={id:n,name:e.name,rules:e.rules.map((i,s)=>({id:`rule-${n}-${s}`,...i})),shareStatus:"NOT_SHARED"};return this.ruleGroups.set(n,r),r}createBlockRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"BLOCK",blockResponse:e.blockResponse||"NODATA",blockOverrideDomain:e.blockOverrideDomain,firewallDomainListId:e.domainListId}]})}createAllowRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"ALLOW",firewallDomainListId:e.domainListId}]})}createDNSFirewall(e){let n=`firewall-${Date.now()}-${this.firewallCounter++}`,r={id:n,name:e.name,firewallRuleGroupAssociations:e.ruleGroupAssociations.map((i,s)=>({id:`assoc-${n}-${s}`,vpcId:e.vpcId,firewallRuleGroupId:i.firewallRuleGroupId,priority:i.priority,mutationProtection:i.mutationProtection||"DISABLED",status:"COMPLETE"}))};return this.firewalls.set(n,r),r}createMalwareProtectionFirewall(e){let n=this.createFirewallDomainList({name:`${e.name}-malware-domains`,domains:e.maliciousDomains}),r=this.createBlockRule({name:`${e.name}-block-malware`,priority:100,domainListId:n.id,blockResponse:"NXDOMAIN"});return this.createDNSFirewall({name:e.name,vpcId:e.vpcId,ruleGroupAssociations:[{firewallRuleGroupId:r.id,priority:100,mutationProtection:"ENABLED"}]})}getEndpoint(e){return this.endpoints.get(e)}listEndpoints(e){let n=Array.from(this.endpoints.values());return e?n.filter((r)=>r.direction===e):n}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((n)=>({SubnetId:n.subnetId,...n.ip&&{Ip:n.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((n)=>({Ip:n.ip,Port:n.port||53}))},...e.resolverEndpointId&&{ResolverEndpointId:e.resolverEndpointId}}}}generateFirewallRuleGroupCF(e){return{Type:"AWS::Route53Resolver::FirewallRuleGroup",Properties:{Name:e.name,FirewallRules:e.rules.map((n)=>({Name:n.name,Priority:n.priority,Action:n.action,FirewallDomainListId:n.firewallDomainListId,...n.blockResponse&&{BlockResponse:n.blockResponse},...n.blockOverrideDomain&&{BlockOverrideDomain:n.blockOverrideDomain},...n.blockOverrideTTL&&{BlockOverrideTtl:n.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 nh=new Zl;class ed{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 n=`bounce-${Date.now()}-${this.bounceCounter++}`,r={id:n,...e};if(this.bounces.set(n,r),e.bounceType==="Permanent")this.addToSuppressionList({emailAddress:e.recipient,reason:"BOUNCE"});return r}recordComplaint(e){let n=`complaint-${Date.now()}-${this.complaintCounter++}`,r={id:n,...e};this.complaints.set(n,r);for(let i of e.recipients)this.addToSuppressionList({emailAddress:i,reason:"COMPLAINT"});return r}createBounceHandler(e){let n=`handler-${Date.now()}-${this.handlerCounter++}`,r={id:n,...e};return this.handlers.set(n,r),r}createAutomaticBounceHandler(e){return this.createBounceHandler({name:e.name,bounceThreshold:5,complaintThreshold:0.1,suppressionDuration:2592000,autoSuppress:!0,notificationTopicArn:e.notificationTopicArn})}addToSuppressionList(e){let n=`suppression-${Date.now()}-${this.suppressionCounter++}`,r=e.expirationDays?new Date(Date.now()+e.expirationDays*24*60*60*1000):void 0,i={id:n,emailAddress:e.emailAddress,reason:e.reason,suppressedAt:new Date,expiresAt:r,bounceCount:e.reason==="BOUNCE"?1:0,complaintCount:e.reason==="COMPLAINT"?1:0};return this.suppressionList.set(e.emailAddress,i),i}removeFromSuppressionList(e){return this.suppressionList.delete(e)}isSuppressed(e){let n=this.suppressionList.get(e);if(!n)return!1;if(n.expiresAt&&n.expiresAt<new Date)return this.suppressionList.delete(e),!1;return!0}getBounceStatistics(e,n){let r=Array.from(this.bounces.values()).filter((p)=>p.timestamp>=e&&p.timestamp<=n),i=r.length,s=r.filter((p)=>p.bounceType==="Permanent").length,a=r.filter((p)=>p.bounceType==="Transient").length,c=i*10,u=i/c*100,d=new Map;for(let p of r)d.set(p.recipient,(d.get(p.recipient)||0)+1);let m=Array.from(d.entries()).map(([p,g])=>({email:p,count:g})).sort((p,g)=>g.count-p.count).slice(0,10);return{totalBounces:i,permanentBounces:s,transientBounces:a,bounceRate:u,topRecipients:m}}getComplaintStatistics(e,n){let r=Array.from(this.complaints.values()).filter((d)=>d.timestamp>=e&&d.timestamp<=n),i=r.length,s=new Set;for(let d of r)for(let m of d.recipients)s.add(m);let a=s.size,c=i*1000,u=i/c*100;return{totalComplaints:i,uniqueComplainters:a,complaintRate:u}}calculateReputationMetrics(){let e=`metrics-${Date.now()}-${this.metricsCounter++}`,n=new Date,r=new Date(n.getTime()-86400000),i=this.getBounceStatistics(r,n),s=this.getComplaintStatistics(r,n),a;if(i.bounceRate>10||s.complaintRate>0.5)a="Shutdown";else if(i.bounceRate>5||s.complaintRate>0.1)a="Probation";else if(i.bounceRate>2||s.complaintRate>0.05)a="Warning";else a="Good";let c={id:e,timestamp:n,bounceRate:i.bounceRate,complaintRate:s.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:i.totalBounces*10,reputationStatus:a};return this.metrics.set(e,c),c}getBounces(e){let n=Array.from(this.bounces.values());return e?n.filter((r)=>r.messageId===e):n}getComplaints(e){let n=Array.from(this.complaints.values());return e?n.filter((r)=>r.messageId===e):n}listSuppressionList(e){let n=Array.from(this.suppressionList.values());return e?n.filter((r)=>r.reason===e):n}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 ih=new ed;class td{events=new Map;campaigns=new Map;reports=new Map;abTests=new Map;eventCounter=0;campaignCounter=0;reportCounter=0;abTestCounter=0;trackEvent(e){let n=`event-${Date.now()}-${this.eventCounter++}`,r={id:n,...e};if(this.events.set(n,r),e.tags?.campaignId)this.updateCampaignStats(e.tags.campaignId,e.eventType);return r}trackOpen(e){return this.trackEvent({...e,eventType:"open",timestamp:new Date})}trackClick(e){return this.trackEvent({...e,eventType:"click",timestamp:new Date})}createCampaign(e){let n=`campaign-${Date.now()}-${this.campaignCounter++}`,r={id:n,sentCount:0,deliveredCount:0,openCount:0,clickCount:0,bounceCount:0,complaintCount:0,createdAt:new Date,...e};return this.campaigns.set(n,r),r}updateCampaignStats(e,n){let r=this.campaigns.get(e);if(!r)return;switch(n){case"send":r.sentCount++;break;case"delivery":r.deliveredCount++;break;case"open":r.openCount++;break;case"click":r.clickCount++;break;case"bounce":r.bounceCount++;break;case"complaint":r.complaintCount++;break}}generateReport(e){let n=`report-${Date.now()}-${this.reportCounter++}`,r=Array.from(this.events.values()).filter((C)=>{let E=C.timestamp>=e.startDate&&C.timestamp<=e.endDate,D=!e.campaignId||C.tags?.campaignId===e.campaignId;return E&&D}),i=r.filter((C)=>C.eventType==="send").length,s=r.filter((C)=>C.eventType==="delivery").length,a=r.filter((C)=>C.eventType==="open").length,c=r.filter((C)=>C.eventType==="click").length,u=r.filter((C)=>C.eventType==="bounce").length,d=r.filter((C)=>C.eventType==="complaint").length,m=i>0?s/i*100:0,p=s>0?a/s*100:0,g=s>0?c/s*100:0,y=a>0?c/a*100:0,f=i>0?u/i*100:0,h=s>0?d/s*100:0,S=new Map;for(let C of r)if(C.eventType==="click"){let E=C;S.set(E.link,(S.get(E.link)||0)+1)}let A=Array.from(S.entries()).map(([C,E])=>({link:C,clicks:E})).sort((C,E)=>E.clicks-C.clicks).slice(0,10),R={desktop:0,mobile:0,tablet:0,unknown:0};for(let C of r)if(C.eventType==="open"||C.eventType==="click"){let E=C.userAgent.toLowerCase();if(E.includes("mobile"))R.mobile++;else if(E.includes("tablet"))R.tablet++;else if(E.includes("mozilla"))R.desktop++;else R.unknown++}let P={id:n,campaignId:e.campaignId,startDate:e.startDate,endDate:e.endDate,totalSent:i,totalDelivered:s,totalOpened:a,totalClicked:c,totalBounced:u,totalComplaints:d,deliveryRate:m,openRate:p,clickRate:g,clickToOpenRate:y,bounceRate:f,complaintRate:h,topLinks:A,deviceBreakdown:R,locationBreakdown:{}};return this.reports.set(n,P),P}createABTest(e){let n=`abtest-${Date.now()}-${this.abTestCounter++}`,r={id:n,name:e.name,variants:e.variants.map((i,s)=>({id:`variant-${n}-${s}`,sentCount:0,openCount:0,clickCount:0,conversionCount:0,...i})),status:"draft"};return this.abTests.set(n,r),r}startABTest(e){let n=this.abTests.get(e);if(!n)throw Error(`A/B test not found: ${e}`);return n.status="running",n.startedAt=new Date,n}completeABTest(e){let n=this.abTests.get(e);if(!n)throw Error(`A/B test not found: ${e}`);let r=n.variants[0],i=0;for(let s of n.variants){let a=s.sentCount>0?s.openCount/s.sentCount:0;if(a>i)i=a,r=s}return n.status="completed",n.completedAt=new Date,n.winner=r.id,n}getCampaign(e){return this.campaigns.get(e)}listCampaigns(){return Array.from(this.campaigns.values())}getEvents(e){let n=Array.from(this.events.values());if(e?.messageId)n=n.filter((r)=>r.messageId===e.messageId);if(e?.eventType)n=n.filter((r)=>r.eventType===e.eventType);if(e?.startDate)n=n.filter((r)=>r.timestamp>=e.startDate);if(e?.endDate)n=n.filter((r)=>r.timestamp<=e.endDate);return n}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 oh=new td;class rd{dashboards=new Map;warmupPlans=new Map;domainReputations=new Map;dashboardCounter=0;warmupCounter=0;domainCounter=0;getReputationDashboard(){let e=`dashboard-${Date.now()}-${this.dashboardCounter++}`,n=Math.random()*5,r=Math.random()*0.5,i=Math.floor(Math.random()*10),s=Math.max(0,100-n*10-r*100-i*2),a=[];if(n>2)a.push("Reduce bounce rate by cleaning email list");if(r>0.1)a.push("Review email content and unsubscribe process");if(i>5)a.push("Improve email relevance and targeting");let c={id:e,timestamp:new Date,overallScore:s,bounceRate:n,complaintRate:r,spamReports:i,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:a};return this.dashboards.set(e,c),c}checkBlacklists(){return["Spamhaus ZEN","Spamcop","SORBS","Barracuda","URIBL"].map((n)=>({listName:n,listed:Math.random()>0.95,delistUrl:`https://www.${n.toLowerCase().replace(/\s/g,"")}.org/delist`}))}createWarmupPlan(e){let n=`warmup-${Date.now()}-${this.warmupCounter++}`,r=[],i=(e.targetDailyLimit-e.initialDailyLimit)/e.durationDays;for(let a=0;a<e.durationDays;a++)r.push(Math.floor(e.initialDailyLimit+i*a));let s={id:n,name:e.name,startDate:new Date,currentDay:1,totalDays:e.durationDays,dailyLimits:r,currentLimit:r[0],status:"active"};return this.warmupPlans.set(n,s),s}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 n=this.warmupPlans.get(e);if(!n)throw Error(`Warmup plan not found: ${e}`);if(n.currentDay<n.totalDays)n.currentDay++,n.currentLimit=n.dailyLimits[n.currentDay-1];if(n.currentDay>=n.totalDays)n.status="completed";return n}trackDomainReputation(e){let n=`domain-${Date.now()}-${this.domainCounter++}`,r=e.delivered/e.totalSent*100,i=e.delivered>0?e.opened/e.delivered*100:0,s=e.delivered>0?e.clicked/e.delivered*100:0,a=e.bounced/e.totalSent*100,c=e.delivered>0?e.complained/e.delivered*100:0,u=i*0.4+s*0.6,d=Math.max(0,100-a*10-c*100+u*0.2),m={id:n,domain:e.domain,reputationScore:d,totalSent:e.totalSent,deliveryRate:r,openRate:i,clickRate:s,bounceRate:a,complaintRate:c,engagementScore:u};return this.domainReputations.set(e.domain,m),m}getDomainReputation(e){return this.domainReputations.get(e)}listDomainReputations(){return Array.from(this.domainReputations.values())}getWarmupPlan(e){return this.warmupPlans.get(e)}listWarmupPlans(){return Array.from(this.warmupPlans.values())}clear(){this.dashboards.clear(),this.warmupPlans.clear(),this.domainReputations.clear(),this.dashboardCounter=0,this.warmupCounter=0,this.domainCounter=0}}var sh=new rd;class nd{templates=new Map;versions=new Map;tests=new Map;templateCounter=0;testCounter=0;createTemplate(e){let n=`template-${Date.now()}-${this.templateCounter++}`,r=this.extractVariables(e.subject+e.htmlPart+e.textPart),i={id:n,variables:r,createdAt:new Date,updatedAt:new Date,version:1,...e};return this.templates.set(n,i),this.addVersion({templateId:n,version:1,subject:e.subject,htmlPart:e.htmlPart,textPart:e.textPart,createdBy:"system"}),i}createWelcomeTemplate(e){return this.createTemplate({name:e.name,subject:"Welcome to {{companyName}}!",htmlPart:`
|
|
3749
|
+
COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let u={sizeBefore:n.totalSize,sizeAfter:n.totalSize*0.6,timeBefore:300,timeAfter:120},d={id:r,name:`Optimization for ${n.imageId}`,recommendations:i,estimatedSavings:u};return this.optimizations.set(r,d),d}getBuildConfig(e){return this.configs.get(e)}listBuildConfigs(){return Array.from(this.configs.values())}getMultiStageConfig(e){return this.multiStageConfigs.get(e)}listMultiStageConfigs(){return Array.from(this.multiStageConfigs.values())}getOptimization(e){return this.optimizations.get(e)}listOptimizations(){return Array.from(this.optimizations.values())}clear(){this.configs.clear(),this.multiStageConfigs.clear(),this.optimizations.clear(),this.analyses.clear(),this.configCounter=0,this.multiStageCounter=0,this.optimizationCounter=0,this.analysisCounter=0}}var ch=new td;class rc{registries=new Map;credentials=new Map;registryCounter=0;credentialsCounter=0;createRegistry(e){let n=`registry-${Date.now()}-${this.registryCounter++}`,r={id:n,...e};return this.registries.set(n,r),r}createECRRepository(e){return this.createRegistry({name:e.name,registryType:"ecr",repositoryUri:`123456789012.dkr.ecr.${e.region||"us-east-1"}.amazonaws.com/${e.name}`,region:e.region||"us-east-1",encryption:{encryptionType:e.encryption||"AES256",kmsKeyId:e.kmsKeyId},scanning:{scanOnPush:e.scanOnPush??!0}})}createManagedRepository(e){let n=this.createECRRepository({name:e.name,region:e.region,scanOnPush:!0,encryption:"KMS"});return n.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"}}]},n}enableReplication(e,n){let r=this.registries.get(e);if(!r)throw Error(`Registry not found: ${e}`);return r.replication={enabled:!0,destinations:n},r}createCredentials(e){let n=`creds-${Date.now()}-${this.credentialsCounter++}`,r={id:n,...e};return this.credentials.set(n,r),r}getRegistry(e){return this.registries.get(e)}listRegistries(){return Array.from(this.registries.values())}generateECRRepositoryCF(e){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:e.name,ImageScanningConfiguration:{ScanOnPush:e.scanning?.scanOnPush??!1},EncryptionConfiguration:{EncryptionType:e.encryption?.encryptionType||"AES256",...e.encryption?.kmsKeyId&&{KmsKey:e.encryption.kmsKeyId}},ImageTagMutability:"MUTABLE",...e.lifecycle&&{LifecyclePolicy:{LifecyclePolicyText:JSON.stringify({rules:e.lifecycle.rules})}}}}}generateReplicationConfigCF(e){return{Type:"AWS::ECR::ReplicationConfiguration",Properties:{ReplicationConfiguration:{Rules:e.destinations.map((n)=>({Destinations:[{Region:n.region,...n.registryId&&{RegistryId:n.registryId}}]}))}}}}clear(){this.registries.clear(),this.credentials.clear(),this.registryCounter=0,this.credentialsCounter=0}}var Dp=new rc;class nc{meshes=new Map;virtualNodes=new Map;virtualRouters=new Map;virtualGateways=new Map;meshCounter=0;nodeCounter=0;routerCounter=0;gatewayCounter=0;createMesh(e){let n=`mesh-${Date.now()}-${this.meshCounter++}`,r={id:n,...e};return this.meshes.set(n,r),r}createAppMesh(e){return this.createMesh({name:e.name,meshType:"app_mesh",services:e.services,virtualNodes:[],virtualRouters:[],virtualGateways:[]})}createVirtualNode(e){let n=`vnode-${Date.now()}-${this.nodeCounter++}`,r={id:n,...e};return this.virtualNodes.set(n,r),r}createHTTPVirtualNode(e){return this.createVirtualNode({name:e.name,serviceName:e.serviceName,listeners:[{port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3},timeout:{perRequest:15000,idle:300000}}],serviceDiscovery:{type:"aws_cloud_map",namespace:e.namespace,serviceName:e.serviceName}})}createVirtualRouter(e){let n=`vrouter-${Date.now()}-${this.routerCounter++}`,r={id:n,...e};return this.virtualRouters.set(n,r),r}createCanaryRoute(e){return this.createVirtualRouter({name:e.name,listeners:[{port:e.port,protocol:e.protocol}],routes:[{name:"canary-route",match:{prefix:"/"},action:{weightedTargets:[{virtualNode:e.stableTarget,weight:100-e.canaryWeight},{virtualNode:e.canaryTarget,weight:e.canaryWeight}]},retryPolicy:{maxRetries:3,perRetryTimeout:5000,httpRetryEvents:["server-error","gateway-error"],tcpRetryEvents:["connection-error"]}}]})}createVirtualGateway(e){let n=`vgateway-${Date.now()}-${this.gatewayCounter++}`,r={id:n,...e};return this.virtualGateways.set(n,r),r}createIngressGateway(e){let n={port:e.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3}};if(e.enableTLS&&e.certificateArn)n.tls={mode:"STRICT",certificate:{acm:e.certificateArn}};return this.createVirtualGateway({name:e.name,listeners:[n],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,n){return{Type:"AWS::AppMesh::VirtualNode",Properties:{MeshName:n,VirtualNodeName:e.name,Spec:{Listeners:e.listeners.map((r)=>({PortMapping:{Port:r.port,Protocol:r.protocol},...r.healthCheck&&{HealthCheck:{Protocol:r.healthCheck.protocol,...r.healthCheck.path&&{Path:r.healthCheck.path},IntervalMillis:r.healthCheck.interval*1000,TimeoutMillis:r.healthCheck.timeout*1000,HealthyThreshold:r.healthCheck.healthyThreshold,UnhealthyThreshold:r.healthCheck.unhealthyThreshold}}})),ServiceDiscovery:{AWSCloudMap:{NamespaceName:e.serviceDiscovery.namespace,ServiceName:e.serviceDiscovery.serviceName}}}}}}generateVirtualRouterCF(e,n){return{Type:"AWS::AppMesh::VirtualRouter",Properties:{MeshName:n,VirtualRouterName:e.name,Spec:{Listeners:e.listeners.map((r)=>({PortMapping:{Port:r.port,Protocol:r.protocol}}))}}}}clear(){this.meshes.clear(),this.virtualNodes.clear(),this.virtualRouters.clear(),this.virtualGateways.clear(),this.meshCounter=0,this.nodeCounter=0,this.routerCounter=0,this.gatewayCounter=0}}var kp=new nc;class rd{layers=new Map;versions=new Map;permissions=new Map;layerCounter=0;versionCounter=0;permissionCounter=0;createLayer(e){let n=`layer-${Date.now()}-${this.layerCounter++}`,r=1,i={id:n,layerArn:`arn:aws:lambda:us-east-1:123456789012:layer:${e.layerName}:1`,version:1,...e};return this.layers.set(n,i),i}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 n=this.layers.get(e);if(!n)throw Error(`Layer not found: ${e}`);let r=`version-${Date.now()}-${this.versionCounter++}`,i=n.version+1,s={id:r,layerName:n.layerName,version:i,createdAt:new Date,compatibleRuntimes:n.compatibleRuntimes,size:n.size,codeHash:this.generateHash()};return this.versions.set(r,s),n.version=i,n.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${n.layerName}:${i}`,s}addPermission(e){let n=`permission-${Date.now()}-${this.permissionCounter++}`,r={id:n,layerName:e.layerName,version:e.version,principal:e.principal,action:"lambda:GetLayerVersion",organizationId:e.organizationId};return this.permissions.set(n,r),r}generateHash(){return Math.random().toString(36).substring(2,15)}getLayer(e){return this.layers.get(e)}listLayers(){return Array.from(this.layers.values())}getLayerVersions(e){return Array.from(this.versions.values()).filter((n)=>n.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 lh=new rd;class nd{versions=new Map;aliases=new Map;deployments=new Map;versionCounter=0;aliasCounter=0;deploymentCounter=0;publishVersion(e){let n=`version-${Date.now()}-${this.versionCounter++}`,r=this.getNextVersionNumber(e.functionName),i={id:n,functionName:e.functionName,version:r.toString(),functionArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${r}`,codeHash:this.generateHash(),description:e.description,runtime:e.runtime,memorySize:e.memorySize,timeout:e.timeout,publishedAt:new Date};return this.versions.set(n,i),i}getNextVersionNumber(e){let n=Array.from(this.versions.values()).filter((r)=>r.functionName===e).map((r)=>parseInt(r.version));return n.length>0?Math.max(...n)+1:1}createAlias(e){let n=`alias-${Date.now()}-${this.aliasCounter++}`,r={id:n,aliasArn:`arn:aws:lambda:us-east-1:123456789012:function:${e.functionName}:${e.aliasName}`,revisionId:this.generateHash(),...e};return this.aliases.set(n,r),r}createProductionAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"production",functionVersion:e.version,description:"Production alias"})}createStagingAlias(e){return this.createAlias({functionName:e.functionName,aliasName:"staging",functionVersion:e.version,description:"Staging alias"})}updateAlias(e,n){let r=this.aliases.get(e);if(!r)throw Error(`Alias not found: ${e}`);return r.functionVersion=n,r.revisionId=this.generateHash(),r}configureWeightedRouting(e,n){let r=this.aliases.get(e);if(!r)throw Error(`Alias not found: ${e}`);return r.routingConfig={additionalVersionWeights:n},r}createCanaryDeployment(e){let n=`deployment-${Date.now()}-${this.deploymentCounter++}`,r=Array.from(this.aliases.values()).find((s)=>s.functionName===e.functionName&&s.aliasName===e.aliasName);if(!r)r=this.createAlias({functionName:e.functionName,aliasName:e.aliasName,functionVersion:e.fromVersion});this.configureWeightedRouting(r.id,{[e.toVersion]:e.canaryWeight});let i={id:n,functionName:e.functionName,fromVersion:e.fromVersion,toVersion:e.toVersion,aliasName:e.aliasName,strategy:"canary",status:"in_progress",startedAt:new Date};return this.deployments.set(n,i),i}completeDeployment(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r=Array.from(this.aliases.values()).find((i)=>i.functionName===n.functionName&&i.aliasName===n.aliasName);if(r)r.functionVersion=n.toVersion,r.routingConfig=void 0;return n.status="completed",n.completedAt=new Date,n}rollbackDeployment(e){let n=this.deployments.get(e);if(!n)throw Error(`Deployment not found: ${e}`);let r=Array.from(this.aliases.values()).find((i)=>i.functionName===n.functionName&&i.aliasName===n.aliasName);if(r)r.functionVersion=n.fromVersion,r.routingConfig=void 0;return n.status="failed",n.completedAt=new Date,n}generateHash(){return Math.random().toString(36).substring(2,15)}getVersion(e){return this.versions.get(e)}listVersions(e){let n=Array.from(this.versions.values());return e?n.filter((r)=>r.functionName===e):n}getAlias(e){return this.aliases.get(e)}listAliases(e){let n=Array.from(this.aliases.values());return e?n.filter((r)=>r.functionName===e):n}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(([n,r])=>({FunctionVersion:n,FunctionWeight:r}))}}}}}clear(){this.versions.clear(),this.aliases.clear(),this.deployments.clear(),this.versionCounter=0,this.aliasCounter=0,this.deploymentCounter=0}}var dh=new nd;class id{configs=new Map;provisionedConfigs=new Map;schedules=new Map;autoScalingConfigs=new Map;configCounter=0;provisionedCounter=0;scheduleCounter=0;autoScalingCounter=0;setReservedConcurrency(e){let n=`concurrency-${Date.now()}-${this.configCounter++}`,r={id:n,functionName:e.functionName,reservedConcurrency:e.reservedConcurrency};return this.configs.set(n,r),r}setProvisionedConcurrency(e){let n=`provisioned-${Date.now()}-${this.provisionedCounter++}`,r={id:n,functionName:e.functionName,qualifier:e.qualifier,provisionedConcurrentExecutions:e.provisionedConcurrentExecutions,status:"pending",lastModified:new Date};return this.provisionedConfigs.set(n,r),setTimeout(()=>{r.status="ready",r.allocatedConcurrency=e.provisionedConcurrentExecutions,r.availableConcurrency=e.provisionedConcurrentExecutions},100),r}configureWarmPool(e){return this.setProvisionedConcurrency({functionName:e.functionName,qualifier:e.alias,provisionedConcurrentExecutions:e.minInstances})}createSchedule(e){let n=`schedule-${Date.now()}-${this.scheduleCounter++}`,r={id:n,...e};return this.schedules.set(n,r),r}createBusinessHoursSchedule(e){return this.createSchedule({name:`${e.functionName}-business-hours`,functionName:e.functionName,qualifier:e.qualifier,schedule:[{name:"business-hours",cronExpression:"0 8 * * MON-FRI",targetConcurrency:e.businessHoursConcurrency},{name:"off-hours",cronExpression:"0 18 * * MON-FRI",targetConcurrency:e.offHoursConcurrency},{name:"weekend",cronExpression:"0 0 * * SAT",targetConcurrency:e.offHoursConcurrency}]})}configureAutoScaling(e){let n=`autoscaling-${Date.now()}-${this.autoScalingCounter++}`,r={id:n,...e};return this.autoScalingConfigs.set(n,r),r}configurePredictiveScaling(e){return this.configureAutoScaling({functionName:e.functionName,qualifier:e.qualifier,minCapacity:e.baselineCapacity,maxCapacity:e.peakCapacity,targetUtilization:0.7,scaleInCooldown:300,scaleOutCooldown:60})}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getProvisionedConfig(e){return this.provisionedConfigs.get(e)}listProvisionedConfigs(){return Array.from(this.provisionedConfigs.values())}generateReservedConcurrencyCF(e){return{Type:"AWS::Lambda::Function",Properties:{FunctionName:e.functionName,ReservedConcurrentExecutions:e.reservedConcurrency}}}generateProvisionedConcurrencyCF(e){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.functionName,Name:e.qualifier,ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:e.provisionedConcurrentExecutions}}}}generateAutoScalingTargetCF(e){return{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{ServiceNamespace:"lambda",ResourceId:`function:${e.functionName}:${e.qualifier}`,ScalableDimension:"lambda:function:ProvisionedConcurrentExecutions",MinCapacity:e.minCapacity,MaxCapacity:e.maxCapacity}}}generateAutoScalingPolicyCF(e){return{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e.functionName}-autoscaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:`${e.functionName}AutoScalingTarget`},TargetTrackingScalingPolicyConfiguration:{TargetValue:e.targetUtilization*100,PredefinedMetricSpecification:{PredefinedMetricType:"LambdaProvisionedConcurrencyUtilization"},ScaleInCooldown:e.scaleInCooldown||300,ScaleOutCooldown:e.scaleOutCooldown||60}}}}clear(){this.configs.clear(),this.provisionedConfigs.clear(),this.schedules.clear(),this.autoScalingConfigs.clear(),this.configCounter=0,this.provisionedCounter=0,this.scheduleCounter=0,this.autoScalingCounter=0}}var uh=new id;class od{destinations=new Map;records=new Map;eventBridgeDestinations=new Map;destinationCounter=0;recordCounter=0;eventBridgeCounter=0;configureDestinations(e){let n=`destination-${Date.now()}-${this.destinationCounter++}`,r={id:n,...e};return this.destinations.set(n,r),r}configureSQSDestination(e){let n={type:"sqs",arn:e.queueArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureSNSDestination(e){let n={type:"sns",arn:e.topicArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureEventBridgeDestination(e){let n={type:"eventbridge",arn:e.eventBusArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n:void 0,maxEventAge:21600,maxRetries:2})}configureLambdaDestination(e){let n={type:"lambda",arn:e.destinationFunctionArn};return this.configureDestinations({functionName:e.functionName,successDestination:e.onSuccess?n:void 0,failureDestination:e.onFailure?n: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 n=`eventbridge-${Date.now()}-${this.eventBridgeCounter++}`,r={id:n,functionName:e.functionName,eventBusArn:e.eventBusArn,detailType:e.detailType||"Lambda Function Invocation Result",source:e.source||`lambda.${e.functionName}`};return this.eventBridgeDestinations.set(n,r),r}sendToDestination(e){let n=Array.from(this.destinations.values()).find((a)=>a.functionName===e.functionName);if(!n)return null;let r=e.status==="success"?n.successDestination:n.failureDestination;if(!r)return null;let i=`record-${Date.now()}-${this.recordCounter++}`,s={id:i,timestamp:new Date,functionName:e.functionName,requestId:e.requestId,status:e.status,destinationType:r.type,destinationArn:r.arn,payload:e.payload,error:e.error};return this.records.set(i,s),s}getDestination(e){return this.destinations.get(e)}listDestinations(e){let n=Array.from(this.destinations.values());return e?n.filter((r)=>r.functionName===e):n}getDestinationRecords(e){let n=Array.from(this.records.values());return e?n.filter((r)=>r.functionName===e):n}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 ph=new od;class sd{vpcConfigs=new Map;endpoints=new Map;networkInterfaces=new Map;connectivity=new Map;configCounter=0;endpointCounter=0;eniCounter=0;connectivityCounter=0;configureVPC(e){let n=`vpc-config-${Date.now()}-${this.configCounter++}`,r={id:n,...e};this.vpcConfigs.set(n,r);for(let i of e.subnetIds)this.createNetworkInterface({functionName:e.functionName,subnetId:i});return r}configurePrivateVPC(e){return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.privateSubnetIds,securityGroupIds:[e.securityGroupId],ipv6Allowed:!1})}configureMultiAZVPC(e){if(e.subnetIds.length<2)throw Error("Multi-AZ configuration requires at least 2 subnets");return this.configureVPC({functionName:e.functionName,vpcId:e.vpcId,subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds})}createVPCEndpoint(e){let n=`endpoint-${Date.now()}-${this.endpointCounter++}`,r={id:n,...e};return this.endpoints.set(n,r),r}createS3Endpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.s3",endpointType:"Gateway",privateDnsEnabled:!1})}createDynamoDBEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.dynamodb",endpointType:"Gateway",privateDnsEnabled:!1})}createSecretsManagerEndpoint(e){return this.createVPCEndpoint({vpcId:e.vpcId,serviceName:"com.amazonaws.us-east-1.secretsmanager",endpointType:"Interface",subnetIds:e.subnetIds,securityGroupIds:e.securityGroupIds,privateDnsEnabled:!0})}createNetworkInterface(e){let n=`eni-${Date.now()}-${this.eniCounter++}`,r={id:n,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(n,r),setTimeout(()=>{r.status="available"},100),r}analyzeConnectivity(e){let n=`connectivity-${Date.now()}-${this.connectivityCounter++}`,r=Array.from(this.vpcConfigs.values()).find((d)=>d.functionName===e.functionName),i=Array.from(this.endpoints.values()).filter((d)=>d.vpcId===r?.vpcId).map((d)=>d.serviceName),s=[],a=e.hasNATGateway??!1,c=e.hasInternetGateway??!1;if(!a&&!c)s.push("Add NAT Gateway for internet access");if(!i.includes("com.amazonaws.us-east-1.s3"))s.push("Add S3 VPC endpoint to reduce NAT costs");if(!i.includes("com.amazonaws.us-east-1.dynamodb"))s.push("Add DynamoDB VPC endpoint for private access");let u={id:n,functionName:e.functionName,hasInternetAccess:a||c,hasNATGateway:a,hasVPCEndpoints:i.length>0,endpoints:i,recommendations:s};return this.connectivity.set(n,u),u}getVPCConfig(e){return this.vpcConfigs.get(e)}listVPCConfigs(e){let n=Array.from(this.vpcConfigs.values());return e?n.filter((r)=>r.functionName===e):n}getNetworkInterfaces(e){return Array.from(this.networkInterfaces.values()).filter((n)=>n.functionName===e)}listVPCEndpoints(e){let n=Array.from(this.endpoints.values());return e?n.filter((r)=>r.vpcId===e):n}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((n)=>({IpProtocol:n.protocol,FromPort:n.fromPort,ToPort:n.toPort,...n.cidrIp&&{CidrIp:n.cidrIp},...n.sourceSecurityGroupId&&{SourceSecurityGroupId:n.sourceSecurityGroupId}}))},...e.egressRules&&{SecurityGroupEgress:e.egressRules.map((n)=>({IpProtocol:n.protocol,FromPort:n.fromPort,ToPort:n.toPort,CidrIp:n.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 mh=new sd;class ad{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(e){let n=`dlq-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.dlqConfigs.set(n,r),r}configureSQSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.queueArn,targetType:"sqs",maxReceiveCount:e.maxReceiveCount||3,retentionPeriod:e.retentionPeriod||1209600})}configureSNSDLQ(e){return this.configureDLQ({functionName:e.functionName,targetArn:e.topicArn,targetType:"sns"})}configureDLQWithAlarm(e){let n=this.configureSQSDLQ({functionName:e.functionName,queueArn:e.queueArn});return this.createDLQAlarm({dlqConfigId:n.id,alarmName:`${e.functionName}-dlq-alarm`,threshold:e.alarmThreshold,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0}),n}sendToDLQ(e){let n=`message-${Date.now()}-${this.messageCounter++}`,r={id:n,timestamp:new Date,...e};return this.messages.set(n,r),r}createDLQAlarm(e){let n=`alarm-${Date.now()}-${this.alarmCounter++}`,r={id:n,...e};return this.alarms.set(n,r),r}createAgeAlarm(e){let n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:e.dlqConfigId,alarmName:`${n.functionName}-dlq-age-alarm`,threshold:e.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:e.notificationTopicArn,enabled:!0})}async reprocessMessage(e){let n=this.messages.get(e);if(!n)throw Error(`Message not found: ${e}`);let r=Array.from(this.dlqConfigs.values()).find((a)=>a.functionName===n.functionName);if(!r)throw Error(`DLQ config not found for function: ${n.functionName}`);let i=`reprocess-${Date.now()}-${this.reprocessCounter++}`,s={id:i,dlqConfigId:r.id,messageId:e,status:"pending",startedAt:new Date};return this.reprocessing.set(i,s),setTimeout(()=>{s.status="processing",setTimeout(()=>{let a=Math.random()>0.3;if(s.status=a?"success":"failed",s.completedAt=new Date,!a)s.error="Reprocessing failed - same error occurred";else this.messages.delete(e)},100)},50),s}async batchReprocess(e){let n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);let i=Array.from(this.messages.values()).filter((s)=>s.functionName===n.functionName).slice(0,e.maxMessages||10).map((s)=>this.reprocessMessage(s.id));return Promise.all(i)}getDLQStats(e){let n=this.dlqConfigs.get(e);if(!n)throw Error(`DLQ config not found: ${e}`);let r=Array.from(this.messages.values()).filter((c)=>c.functionName===n.functionName),i={},s=0;for(let c of r)i[c.errorType]=(i[c.errorType]||0)+1,s+=c.attemptCount;let a=r.map((c)=>c.timestamp);return{totalMessages:r.length,oldestMessage:a.length>0?new Date(Math.min(...a.map((c)=>c.getTime()))):void 0,newestMessage:a.length>0?new Date(Math.max(...a.map((c)=>c.getTime()))):void 0,averageAttempts:r.length>0?s/r.length:0,errorTypes:i}}getDLQConfig(e){return this.dlqConfigs.get(e)}listDLQConfigs(){return Array.from(this.dlqConfigs.values())}getDLQMessages(e){let n=this.dlqConfigs.get(e);if(!n)return[];return Array.from(this.messages.values()).filter((r)=>r.functionName===n.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 n=this.dlqConfigs.get(e.dlqConfigId);if(!n)throw Error(`DLQ config not found: ${e.dlqConfigId}`);return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:e.alarmName,AlarmDescription:`DLQ alarm for ${n.functionName}`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:e.evaluationPeriods,Threshold:e.threshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:n.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 gh=new ad;class ic{policies=new Map;healthChecks=new Map;trafficPolicies=new Map;policyCounter=0;healthCheckCounter=0;trafficPolicyCounter=0;createWeightedPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"weighted",...e};return this.policies.set(n,r),r}createLatencyPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"latency",...e};return this.policies.set(n,r),r}createFailoverPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"failover",...e};return this.policies.set(n,r),r}createGeolocationPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"geolocation",...e};return this.policies.set(n,r),r}createGeoproximityPolicy(e){let n=`policy-${Date.now()}-${this.policyCounter++}`,r={id:n,type:"geoproximity",...e};return this.policies.set(n,r),r}createHTTPHealthCheck(e){let n=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:n,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(n,r),setTimeout(()=>{r.healthCheckStatus=Math.random()>0.2?"Healthy":"Unhealthy"},100),r}createTCPHealthCheck(e){let n=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:n,type:"tcp",fullyQualifiedDomainName:e.ipAddress,requestInterval:e.requestInterval||30,failureThreshold:e.failureThreshold||3,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(n,r),setTimeout(()=>{r.healthCheckStatus=Math.random()>0.1?"Healthy":"Unhealthy"},100),r}createCalculatedHealthCheck(e){let n=`health-check-${Date.now()}-${this.healthCheckCounter++}`,r={id:n,type:"calculated",requestInterval:30,failureThreshold:0,healthCheckStatus:"Unknown",...e};return this.healthChecks.set(n,r),setTimeout(()=>{let s=e.childHealthChecks.filter((a)=>this.healthChecks.get(a)?.healthCheckStatus==="Healthy").length;r.healthCheckStatus=s>=e.healthThreshold?"Healthy":"Unhealthy"},150),r}createTrafficPolicy(e){let n=`traffic-policy-${Date.now()}-${this.trafficPolicyCounter++}`,r={id:n,version:1,...e};return this.trafficPolicies.set(n,r),r}createFailoverTrafficPolicy(e){return this.createTrafficPolicy({name:e.name,document:{recordType:e.recordType||"A",startRule:"failover",endpoints:{primary:{type:"value",value:e.primaryEndpoint},secondary:{type:"value",value:e.secondaryEndpoint}},rules:{failover:{ruleType:"failover",primary:"primary",secondary:"secondary"}}}})}createGeoproximityTrafficPolicy(e){let n={},r=[];return e.locations.forEach((i,s)=>{let a=`endpoint${s}`;n[a]={type:"value",value:i.endpoint},r.push({endpointReference:a,region:i.region,latitude:i.latitude,longitude:i.longitude,bias:i.bias})}),this.createTrafficPolicy({name:e.name,document:{recordType:"A",startRule:"geoproximity",endpoints:n,rules:{geoproximity:{ruleType:"geoproximity",locations:r}}}})}getPolicy(e){return this.policies.get(e)}listPolicies(){return Array.from(this.policies.values())}getHealthCheck(e){return this.healthChecks.get(e)}listHealthChecks(){return Array.from(this.healthChecks.values())}getHealthCheckStatus(e){return this.healthChecks.get(e)?.healthCheckStatus||"Unknown"}generateHealthCheckCF(e){let n={Type:"AWS::Route53::HealthCheck",Properties:{HealthCheckConfig:{Type:e.type.toUpperCase(),RequestInterval:e.requestInterval,FailureThreshold:e.failureThreshold,...e.measureLatency&&{MeasureLatency:!0}},HealthCheckTags:[{Key:"Name",Value:e.name}]}};if(e.type==="calculated"){let r=e;n.Properties.HealthCheckConfig.ChildHealthChecks=r.childHealthChecks,n.Properties.HealthCheckConfig.HealthThreshold=r.healthThreshold}else{if(e.ipAddress)n.Properties.HealthCheckConfig.IPAddress=e.ipAddress;if(e.fullyQualifiedDomainName)n.Properties.HealthCheckConfig.FullyQualifiedDomainName=e.fullyQualifiedDomainName;if(e.port)n.Properties.HealthCheckConfig.Port=e.port;if(e.resourcePath)n.Properties.HealthCheckConfig.ResourcePath=e.resourcePath;if(e.enableSNI)n.Properties.HealthCheckConfig.EnableSNI=!0}return n}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 Np=new ic;class cd{configs=new Map;ksks=new Map;validations=new Map;configCounter=0;kskCounter=0;validationCounter=0;enableDNSSEC(e){let n=`dnssec-${Date.now()}-${this.configCounter++}`,r={id:n,hostedZoneId:e.hostedZoneId,status:"SIGNING",signingStatus:"Initializing DNSSEC signing"};if(this.configs.set(n,r),e.kmsKeyArn)this.createKSK({name:`ksk-${e.hostedZoneId}`,hostedZoneId:e.hostedZoneId,kmsKeyArn:e.kmsKeyArn});return setTimeout(()=>{r.status="SIGNED",r.signingStatus="DNSSEC signing complete"},100),r}disableDNSSEC(e){let n=this.configs.get(e);if(!n)throw Error(`DNSSEC config not found: ${e}`);return n.status="DELETING",n.signingStatus="Removing DNSSEC signing",setTimeout(()=>{n.status="NOT_SIGNING",n.signingStatus="DNSSEC signing removed"},100),n}createKSK(e){let n=`ksk-${Date.now()}-${this.kskCounter++}`,r={id:n,status:"ACTIVE",flag:257,keyManagementServiceArn:e.kmsKeyArn,digestAlgorithm:2,keyTag:Math.floor(Math.random()*65535),publicKey:this.generatePublicKey(),...e};r.dnskeyRecord=`${r.flag} 3 8 ${r.publicKey}`;let i=this.generateDigest(r.dnskeyRecord);return r.digestValue=i,r.dsRecord=`${r.keyTag} 8 ${r.digestAlgorithm} ${i}`,this.ksks.set(n,r),r}deactivateKSK(e){let n=this.ksks.get(e);if(!n)throw Error(`KSK not found: ${e}`);return n.status="INACTIVE",n}validateDNSSEC(e){let n=`validation-${Date.now()}-${this.validationCounter++}`,r=e.checkDNSKEY!==!1?Math.random()>0.1:!1,i=e.checkRRSIG!==!1?Math.random()>0.1:!1,s=r&&i,a=[];if(!r)a.push("DNSKEY record not found");if(!i)a.push("RRSIG record not found");let c;if(!r&&!i)c="INSECURE";else if(r&&i&&s)c="VALID";else if(r||i)c="BOGUS",a.push("Invalid signature or incomplete DNSSEC chain");else c="INVALID";let u={id:n,domain:e.domain,validationStatus:c,dnskeyPresent:r,rrsigPresent:i,validSignature:s,errors:a};return this.validations.set(n,u),u}getDNSSECConfig(e){return this.configs.get(e)}listDNSSECConfigs(){return Array.from(this.configs.values())}getKSK(e){return this.ksks.get(e)}listKSKs(e){let n=Array.from(this.ksks.values());return e?n.filter((r)=>r.hostedZoneId===e):n}getDSRecord(e){let n=this.ksks.get(e);if(!n||!n.dsRecord)throw Error("DS record not available");return n.dsRecord}generatePublicKey(){let n="";for(let r=0;r<256;r++)n+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return n}generateDigest(e){let r="";for(let i=0;i<64;i++)r+="0123456789ABCDEF".charAt(Math.floor(Math.random()*16));return r}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 fh=new cd;class ld{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 n=`endpoint-${Date.now()}-${this.endpointCounter++}`,r={id:n,status:"CREATING",...e};return this.endpoints.set(n,r),setTimeout(()=>{r.status="OPERATIONAL",r.ipAddresses.forEach((i)=>{if(!i.ip)i.ip=`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`})},100),r}createInboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"INBOUND",ipAddresses:e.subnetIds.map((n)=>({subnetId:n})),securityGroupIds:e.securityGroupIds})}createOutboundEndpoint(e){return this.createResolverEndpoint({name:e.name,direction:"OUTBOUND",ipAddresses:e.subnetIds.map((n)=>({subnetId:n})),securityGroupIds:e.securityGroupIds})}createResolverRule(e){let n=`rule-${Date.now()}-${this.ruleCounter++}`,r={id:n,status:"CREATING",...e};return this.rules.set(n,r),setTimeout(()=>{r.status="COMPLETE"},100),r}createForwardRule(e){return this.createResolverRule({name:e.name,ruleType:"FORWARD",domainName:e.domainName,targetIps:e.targetIps,resolverEndpointId:e.resolverEndpointId})}createSystemRule(e){return this.createResolverRule({name:e.name,ruleType:"SYSTEM",domainName:e.domainName})}createFirewallDomainList(e){let n=`domain-list-${Date.now()}-${this.domainListCounter++}`,r={id:n,status:"CREATING",...e};return this.domainLists.set(n,r),setTimeout(()=>{r.status="COMPLETE"},100),r}createFirewallRuleGroup(e){let n=`rule-group-${Date.now()}-${this.ruleGroupCounter++}`,r={id:n,name:e.name,rules:e.rules.map((i,s)=>({id:`rule-${n}-${s}`,...i})),shareStatus:"NOT_SHARED"};return this.ruleGroups.set(n,r),r}createBlockRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"BLOCK",blockResponse:e.blockResponse||"NODATA",blockOverrideDomain:e.blockOverrideDomain,firewallDomainListId:e.domainListId}]})}createAllowRule(e){return this.createFirewallRuleGroup({name:e.name,rules:[{name:e.name,priority:e.priority,action:"ALLOW",firewallDomainListId:e.domainListId}]})}createDNSFirewall(e){let n=`firewall-${Date.now()}-${this.firewallCounter++}`,r={id:n,name:e.name,firewallRuleGroupAssociations:e.ruleGroupAssociations.map((i,s)=>({id:`assoc-${n}-${s}`,vpcId:e.vpcId,firewallRuleGroupId:i.firewallRuleGroupId,priority:i.priority,mutationProtection:i.mutationProtection||"DISABLED",status:"COMPLETE"}))};return this.firewalls.set(n,r),r}createMalwareProtectionFirewall(e){let n=this.createFirewallDomainList({name:`${e.name}-malware-domains`,domains:e.maliciousDomains}),r=this.createBlockRule({name:`${e.name}-block-malware`,priority:100,domainListId:n.id,blockResponse:"NXDOMAIN"});return this.createDNSFirewall({name:e.name,vpcId:e.vpcId,ruleGroupAssociations:[{firewallRuleGroupId:r.id,priority:100,mutationProtection:"ENABLED"}]})}getEndpoint(e){return this.endpoints.get(e)}listEndpoints(e){let n=Array.from(this.endpoints.values());return e?n.filter((r)=>r.direction===e):n}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((n)=>({SubnetId:n.subnetId,...n.ip&&{Ip:n.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((n)=>({Ip:n.ip,Port:n.port||53}))},...e.resolverEndpointId&&{ResolverEndpointId:e.resolverEndpointId}}}}generateFirewallRuleGroupCF(e){return{Type:"AWS::Route53Resolver::FirewallRuleGroup",Properties:{Name:e.name,FirewallRules:e.rules.map((n)=>({Name:n.name,Priority:n.priority,Action:n.action,FirewallDomainListId:n.firewallDomainListId,...n.blockResponse&&{BlockResponse:n.blockResponse},...n.blockOverrideDomain&&{BlockOverrideDomain:n.blockOverrideDomain},...n.blockOverrideTTL&&{BlockOverrideTtl:n.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 hh=new ld;class dd{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 n=`bounce-${Date.now()}-${this.bounceCounter++}`,r={id:n,...e};if(this.bounces.set(n,r),e.bounceType==="Permanent")this.addToSuppressionList({emailAddress:e.recipient,reason:"BOUNCE"});return r}recordComplaint(e){let n=`complaint-${Date.now()}-${this.complaintCounter++}`,r={id:n,...e};this.complaints.set(n,r);for(let i of e.recipients)this.addToSuppressionList({emailAddress:i,reason:"COMPLAINT"});return r}createBounceHandler(e){let n=`handler-${Date.now()}-${this.handlerCounter++}`,r={id:n,...e};return this.handlers.set(n,r),r}createAutomaticBounceHandler(e){return this.createBounceHandler({name:e.name,bounceThreshold:5,complaintThreshold:0.1,suppressionDuration:2592000,autoSuppress:!0,notificationTopicArn:e.notificationTopicArn})}addToSuppressionList(e){let n=`suppression-${Date.now()}-${this.suppressionCounter++}`,r=e.expirationDays?new Date(Date.now()+e.expirationDays*24*60*60*1000):void 0,i={id:n,emailAddress:e.emailAddress,reason:e.reason,suppressedAt:new Date,expiresAt:r,bounceCount:e.reason==="BOUNCE"?1:0,complaintCount:e.reason==="COMPLAINT"?1:0};return this.suppressionList.set(e.emailAddress,i),i}removeFromSuppressionList(e){return this.suppressionList.delete(e)}isSuppressed(e){let n=this.suppressionList.get(e);if(!n)return!1;if(n.expiresAt&&n.expiresAt<new Date)return this.suppressionList.delete(e),!1;return!0}getBounceStatistics(e,n){let r=Array.from(this.bounces.values()).filter((p)=>p.timestamp>=e&&p.timestamp<=n),i=r.length,s=r.filter((p)=>p.bounceType==="Permanent").length,a=r.filter((p)=>p.bounceType==="Transient").length,c=i*10,u=i/c*100,d=new Map;for(let p of r)d.set(p.recipient,(d.get(p.recipient)||0)+1);let m=Array.from(d.entries()).map(([p,g])=>({email:p,count:g})).sort((p,g)=>g.count-p.count).slice(0,10);return{totalBounces:i,permanentBounces:s,transientBounces:a,bounceRate:u,topRecipients:m}}getComplaintStatistics(e,n){let r=Array.from(this.complaints.values()).filter((d)=>d.timestamp>=e&&d.timestamp<=n),i=r.length,s=new Set;for(let d of r)for(let m of d.recipients)s.add(m);let a=s.size,c=i*1000,u=i/c*100;return{totalComplaints:i,uniqueComplainters:a,complaintRate:u}}calculateReputationMetrics(){let e=`metrics-${Date.now()}-${this.metricsCounter++}`,n=new Date,r=new Date(n.getTime()-86400000),i=this.getBounceStatistics(r,n),s=this.getComplaintStatistics(r,n),a;if(i.bounceRate>10||s.complaintRate>0.5)a="Shutdown";else if(i.bounceRate>5||s.complaintRate>0.1)a="Probation";else if(i.bounceRate>2||s.complaintRate>0.05)a="Warning";else a="Good";let c={id:e,timestamp:n,bounceRate:i.bounceRate,complaintRate:s.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:i.totalBounces*10,reputationStatus:a};return this.metrics.set(e,c),c}getBounces(e){let n=Array.from(this.bounces.values());return e?n.filter((r)=>r.messageId===e):n}getComplaints(e){let n=Array.from(this.complaints.values());return e?n.filter((r)=>r.messageId===e):n}listSuppressionList(e){let n=Array.from(this.suppressionList.values());return e?n.filter((r)=>r.reason===e):n}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 yh=new dd;class ud{events=new Map;campaigns=new Map;reports=new Map;abTests=new Map;eventCounter=0;campaignCounter=0;reportCounter=0;abTestCounter=0;trackEvent(e){let n=`event-${Date.now()}-${this.eventCounter++}`,r={id:n,...e};if(this.events.set(n,r),e.tags?.campaignId)this.updateCampaignStats(e.tags.campaignId,e.eventType);return r}trackOpen(e){return this.trackEvent({...e,eventType:"open",timestamp:new Date})}trackClick(e){return this.trackEvent({...e,eventType:"click",timestamp:new Date})}createCampaign(e){let n=`campaign-${Date.now()}-${this.campaignCounter++}`,r={id:n,sentCount:0,deliveredCount:0,openCount:0,clickCount:0,bounceCount:0,complaintCount:0,createdAt:new Date,...e};return this.campaigns.set(n,r),r}updateCampaignStats(e,n){let r=this.campaigns.get(e);if(!r)return;switch(n){case"send":r.sentCount++;break;case"delivery":r.deliveredCount++;break;case"open":r.openCount++;break;case"click":r.clickCount++;break;case"bounce":r.bounceCount++;break;case"complaint":r.complaintCount++;break}}generateReport(e){let n=`report-${Date.now()}-${this.reportCounter++}`,r=Array.from(this.events.values()).filter((C)=>{let E=C.timestamp>=e.startDate&&C.timestamp<=e.endDate,D=!e.campaignId||C.tags?.campaignId===e.campaignId;return E&&D}),i=r.filter((C)=>C.eventType==="send").length,s=r.filter((C)=>C.eventType==="delivery").length,a=r.filter((C)=>C.eventType==="open").length,c=r.filter((C)=>C.eventType==="click").length,u=r.filter((C)=>C.eventType==="bounce").length,d=r.filter((C)=>C.eventType==="complaint").length,m=i>0?s/i*100:0,p=s>0?a/s*100:0,g=s>0?c/s*100:0,y=a>0?c/a*100:0,f=i>0?u/i*100:0,h=s>0?d/s*100:0,S=new Map;for(let C of r)if(C.eventType==="click"){let E=C;S.set(E.link,(S.get(E.link)||0)+1)}let A=Array.from(S.entries()).map(([C,E])=>({link:C,clicks:E})).sort((C,E)=>E.clicks-C.clicks).slice(0,10),R={desktop:0,mobile:0,tablet:0,unknown:0};for(let C of r)if(C.eventType==="open"||C.eventType==="click"){let E=C.userAgent.toLowerCase();if(E.includes("mobile"))R.mobile++;else if(E.includes("tablet"))R.tablet++;else if(E.includes("mozilla"))R.desktop++;else R.unknown++}let P={id:n,campaignId:e.campaignId,startDate:e.startDate,endDate:e.endDate,totalSent:i,totalDelivered:s,totalOpened:a,totalClicked:c,totalBounced:u,totalComplaints:d,deliveryRate:m,openRate:p,clickRate:g,clickToOpenRate:y,bounceRate:f,complaintRate:h,topLinks:A,deviceBreakdown:R,locationBreakdown:{}};return this.reports.set(n,P),P}createABTest(e){let n=`abtest-${Date.now()}-${this.abTestCounter++}`,r={id:n,name:e.name,variants:e.variants.map((i,s)=>({id:`variant-${n}-${s}`,sentCount:0,openCount:0,clickCount:0,conversionCount:0,...i})),status:"draft"};return this.abTests.set(n,r),r}startABTest(e){let n=this.abTests.get(e);if(!n)throw Error(`A/B test not found: ${e}`);return n.status="running",n.startedAt=new Date,n}completeABTest(e){let n=this.abTests.get(e);if(!n)throw Error(`A/B test not found: ${e}`);let r=n.variants[0],i=0;for(let s of n.variants){let a=s.sentCount>0?s.openCount/s.sentCount:0;if(a>i)i=a,r=s}return n.status="completed",n.completedAt=new Date,n.winner=r.id,n}getCampaign(e){return this.campaigns.get(e)}listCampaigns(){return Array.from(this.campaigns.values())}getEvents(e){let n=Array.from(this.events.values());if(e?.messageId)n=n.filter((r)=>r.messageId===e.messageId);if(e?.eventType)n=n.filter((r)=>r.eventType===e.eventType);if(e?.startDate)n=n.filter((r)=>r.timestamp>=e.startDate);if(e?.endDate)n=n.filter((r)=>r.timestamp<=e.endDate);return n}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 bh=new ud;class pd{dashboards=new Map;warmupPlans=new Map;domainReputations=new Map;dashboardCounter=0;warmupCounter=0;domainCounter=0;getReputationDashboard(){let e=`dashboard-${Date.now()}-${this.dashboardCounter++}`,n=Math.random()*5,r=Math.random()*0.5,i=Math.floor(Math.random()*10),s=Math.max(0,100-n*10-r*100-i*2),a=[];if(n>2)a.push("Reduce bounce rate by cleaning email list");if(r>0.1)a.push("Review email content and unsubscribe process");if(i>5)a.push("Improve email relevance and targeting");let c={id:e,timestamp:new Date,overallScore:s,bounceRate:n,complaintRate:r,spamReports:i,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:a};return this.dashboards.set(e,c),c}checkBlacklists(){return["Spamhaus ZEN","Spamcop","SORBS","Barracuda","URIBL"].map((n)=>({listName:n,listed:Math.random()>0.95,delistUrl:`https://www.${n.toLowerCase().replace(/\s/g,"")}.org/delist`}))}createWarmupPlan(e){let n=`warmup-${Date.now()}-${this.warmupCounter++}`,r=[],i=(e.targetDailyLimit-e.initialDailyLimit)/e.durationDays;for(let a=0;a<e.durationDays;a++)r.push(Math.floor(e.initialDailyLimit+i*a));let s={id:n,name:e.name,startDate:new Date,currentDay:1,totalDays:e.durationDays,dailyLimits:r,currentLimit:r[0],status:"active"};return this.warmupPlans.set(n,s),s}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 n=this.warmupPlans.get(e);if(!n)throw Error(`Warmup plan not found: ${e}`);if(n.currentDay<n.totalDays)n.currentDay++,n.currentLimit=n.dailyLimits[n.currentDay-1];if(n.currentDay>=n.totalDays)n.status="completed";return n}trackDomainReputation(e){let n=`domain-${Date.now()}-${this.domainCounter++}`,r=e.delivered/e.totalSent*100,i=e.delivered>0?e.opened/e.delivered*100:0,s=e.delivered>0?e.clicked/e.delivered*100:0,a=e.bounced/e.totalSent*100,c=e.delivered>0?e.complained/e.delivered*100:0,u=i*0.4+s*0.6,d=Math.max(0,100-a*10-c*100+u*0.2),m={id:n,domain:e.domain,reputationScore:d,totalSent:e.totalSent,deliveryRate:r,openRate:i,clickRate:s,bounceRate:a,complaintRate:c,engagementScore:u};return this.domainReputations.set(e.domain,m),m}getDomainReputation(e){return this.domainReputations.get(e)}listDomainReputations(){return Array.from(this.domainReputations.values())}getWarmupPlan(e){return this.warmupPlans.get(e)}listWarmupPlans(){return Array.from(this.warmupPlans.values())}clear(){this.dashboards.clear(),this.warmupPlans.clear(),this.domainReputations.clear(),this.dashboardCounter=0,this.warmupCounter=0,this.domainCounter=0}}var Sh=new pd;class md{templates=new Map;versions=new Map;tests=new Map;templateCounter=0;testCounter=0;createTemplate(e){let n=`template-${Date.now()}-${this.templateCounter++}`,r=this.extractVariables(e.subject+e.htmlPart+e.textPart),i={id:n,variables:r,createdAt:new Date,updatedAt:new Date,version:1,...e};return this.templates.set(n,i),this.addVersion({templateId:n,version:1,subject:e.subject,htmlPart:e.htmlPart,textPart:e.textPart,createdBy:"system"}),i}createWelcomeTemplate(e){return this.createTemplate({name:e.name,subject:"Welcome to {{companyName}}!",htmlPart:`
|
|
3752
3750
|
<html>
|
|
3753
3751
|
<body>
|
|
3754
3752
|
<h1>Welcome, {{userName}}!</h1>
|
|
@@ -3768,7 +3766,7 @@ COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let u={si
|
|
|
3768
3766
|
<p>If you didn't request this, please ignore this email.</p>
|
|
3769
3767
|
</body>
|
|
3770
3768
|
</html>
|
|
3771
|
-
`,textPart:"Hi {{userName}}, reset your password at: {{resetUrl}}. This link expires in {{expirationHours}} hours."})}updateTemplate(e,n,r){let i=this.templates.get(e);if(!i)throw Error(`Template not found: ${e}`);if(n.subject)i.subject=n.subject;if(n.htmlPart)i.htmlPart=n.htmlPart;if(n.textPart)i.textPart=n.textPart;return i.version++,i.updatedAt=new Date,i.variables=this.extractVariables(i.subject+i.htmlPart+i.textPart),this.addVersion({templateId:e,version:i.version,subject:i.subject,htmlPart:i.htmlPart,textPart:i.textPart,createdBy:"system",changelog:r}),i}addVersion(e){let r={id:`version-${e.templateId}-${e.version}`,createdAt:new Date,...e},i=this.versions.get(e.templateId)||[];return i.push(r),this.versions.set(e.templateId,i),r}extractVariables(e){let n=/\{\{([^}]+)\}\}/g,r=new Set,i;while((i=n.exec(e))!==null)r.add(i[1].trim());return Array.from(r)}renderTemplate(e,n){let r=this.templates.get(e);if(!r)throw Error(`Template not found: ${e}`);let i=(s)=>s.replace(/\{\{([^}]+)\}\}/g,(a,c)=>{let u=c.trim();return n[u]!==void 0?String(n[u]):a});return{subject:i(r.subject),html:i(r.htmlPart),text:i(r.textPart)}}testTemplate(e,n){let r=`test-${Date.now()}-${this.testCounter++}`,i=this.renderTemplate(e,n),s={id:r,templateId:e,testData:n,renderedSubject:i.subject,renderedHtml:i.html,renderedText:i.text,timestamp:new Date};return this.tests.set(r,s),s}getTemplate(e){return this.templates.get(e)}listTemplates(){return Array.from(this.templates.values())}getTemplateVersions(e){return this.versions.get(e)||[]}revertToVersion(e,n){let r=this.templates.get(e);if(!r)throw Error(`Template not found: ${e}`);let s=(this.versions.get(e)||[]).find((a)=>a.version===n);if(!s)throw Error(`Version ${n} not found for template ${e}`);return r.subject=s.subject,r.htmlPart=s.htmlPart,r.textPart=s.textPart,r.version++,r.updatedAt=new Date,this.addVersion({templateId:e,version:r.version,subject:r.subject,htmlPart:r.htmlPart,textPart:r.textPart,createdBy:"system",changelog:`Reverted to version ${n}`}),r}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
|
|
3769
|
+
`,textPart:"Hi {{userName}}, reset your password at: {{resetUrl}}. This link expires in {{expirationHours}} hours."})}updateTemplate(e,n,r){let i=this.templates.get(e);if(!i)throw Error(`Template not found: ${e}`);if(n.subject)i.subject=n.subject;if(n.htmlPart)i.htmlPart=n.htmlPart;if(n.textPart)i.textPart=n.textPart;return i.version++,i.updatedAt=new Date,i.variables=this.extractVariables(i.subject+i.htmlPart+i.textPart),this.addVersion({templateId:e,version:i.version,subject:i.subject,htmlPart:i.htmlPart,textPart:i.textPart,createdBy:"system",changelog:r}),i}addVersion(e){let r={id:`version-${e.templateId}-${e.version}`,createdAt:new Date,...e},i=this.versions.get(e.templateId)||[];return i.push(r),this.versions.set(e.templateId,i),r}extractVariables(e){let n=/\{\{([^}]+)\}\}/g,r=new Set,i;while((i=n.exec(e))!==null)r.add(i[1].trim());return Array.from(r)}renderTemplate(e,n){let r=this.templates.get(e);if(!r)throw Error(`Template not found: ${e}`);let i=(s)=>s.replace(/\{\{([^}]+)\}\}/g,(a,c)=>{let u=c.trim();return n[u]!==void 0?String(n[u]):a});return{subject:i(r.subject),html:i(r.htmlPart),text:i(r.textPart)}}testTemplate(e,n){let r=`test-${Date.now()}-${this.testCounter++}`,i=this.renderTemplate(e,n),s={id:r,templateId:e,testData:n,renderedSubject:i.subject,renderedHtml:i.html,renderedText:i.text,timestamp:new Date};return this.tests.set(r,s),s}getTemplate(e){return this.templates.get(e)}listTemplates(){return Array.from(this.templates.values())}getTemplateVersions(e){return this.versions.get(e)||[]}revertToVersion(e,n){let r=this.templates.get(e);if(!r)throw Error(`Template not found: ${e}`);let s=(this.versions.get(e)||[]).find((a)=>a.version===n);if(!s)throw Error(`Version ${n} not found for template ${e}`);return r.subject=s.subject,r.htmlPart=s.htmlPart,r.textPart=s.textPart,r.version++,r.updatedAt=new Date,this.addVersion({templateId:e,version:r.version,subject:r.subject,htmlPart:r.htmlPart,textPart:r.textPart,createdBy:"system",changelog:`Reverted to version ${n}`}),r}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 vh=new md;class Wt{static createSearchDomain(e){let{slug:n,environment:r,domainName:i,instanceType:s="t3.small.search",instanceCount:a=1,ebsVolumeSize:c=10,masterUserName:u="admin",masterUserPassword:d}=e,m=i||`${n}-${r}-email-search`;return{[`${n}EmailSearchDomain`]:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:m,EngineVersion:"OpenSearch_2.11",ClusterConfig:{InstanceType:s,InstanceCount:a,DedicatedMasterEnabled:!1,ZoneAwarenessEnabled:!1},EBSOptions:{EBSEnabled:!0,VolumeType:"gp3",VolumeSize:c},NodeToNodeEncryptionOptions:{Enabled:!0},EncryptionAtRestOptions:{Enabled:!0},DomainEndpointOptions:{EnforceHTTPS:!0},AdvancedSecurityOptions:{Enabled:!0,InternalUserDatabaseEnabled:!0,MasterUserOptions:{MasterUserName:u,MasterUserPassword:d||`${n}-search-${Date.now()}`}},AccessPolicies:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:`arn:aws:es:*:*:domain/${m}/*`}]}}}}}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:Wt.IndexerLambdaCode},Environment:{Variables:{OPENSEARCH_ENDPOINT:e.searchDomainEndpoint,EMAIL_BUCKET:e.emailBucket}}}}}}static IndexerLambdaCode=`
|
|
3772
3770
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
3773
3771
|
const https = require('https');
|
|
3774
3772
|
|
|
@@ -3868,7 +3866,7 @@ async function indexDocument(doc) {
|
|
|
3868
3866
|
req.end();
|
|
3869
3867
|
});
|
|
3870
3868
|
}
|
|
3871
|
-
`;static getIndexMapping(){return{mappings:{properties:{messageId:{type:"keyword"},from:{type:"keyword"},fromName:{type:"text"},to:{type:"keyword"},toName:{type:"text"},cc:{type:"keyword"},subject:{type:"text",analyzer:"standard",fields:{keyword:{type:"keyword"}}},body:{type:"text",analyzer:"standard"},bodyPreview:{type:"text"},date:{type:"date"},receivedAt:{type:"date"},hasAttachments:{type:"boolean"},attachmentNames:{type:"keyword"},labels:{type:"keyword"},folder:{type:"keyword"},threadId:{type:"keyword"},isRead:{type:"boolean"},isStarred:{type:"boolean"},mailbox:{type:"keyword"}}},settings:{number_of_shards:1,number_of_replicas:0}}}static buildSearchQuery(e){let n=[],r=[];if(e.query)n.push({multi_match:{query:e.query,fields:["subject^3","body","fromName","toName"],type:"best_fields",fuzziness:"AUTO"}});if(e.from)r.push({term:{from:e.from}});if(e.to)r.push({term:{to:e.to}});if(e.subject)n.push({match_phrase:{subject:e.subject}});if(e.hasAttachments!==void 0)r.push({term:{hasAttachments:e.hasAttachments}});if(e.folder)r.push({term:{folder:e.folder}});if(e.labels&&e.labels.length>0)r.push({terms:{labels:e.labels}});if(e.isRead!==void 0)r.push({term:{isRead:e.isRead}});if(e.dateFrom||e.dateTo){let a={date:{}};if(e.dateFrom)a.date.gte=e.dateFrom;if(e.dateTo)a.date.lte=e.dateTo;r.push({range:a})}let i={bool:{}};if(n.length>0)i.bool.must=n;if(r.length>0)i.bool.filter=r;if(n.length===0&&r.length===0)i.bool.must=[{match_all:{}}];let s=[];if(e.sort==="relevance"&&e.query)s.push({_score:e.sortOrder||"desc"});return s.push({date:e.sortOrder||"desc"}),{query:i,sort:s,from:e.offset||0,size:e.limit||20,highlight:{fields:{subject:{},body:{fragment_size:150,number_of_fragments:3}}}}}}class
|
|
3869
|
+
`;static getIndexMapping(){return{mappings:{properties:{messageId:{type:"keyword"},from:{type:"keyword"},fromName:{type:"text"},to:{type:"keyword"},toName:{type:"text"},cc:{type:"keyword"},subject:{type:"text",analyzer:"standard",fields:{keyword:{type:"keyword"}}},body:{type:"text",analyzer:"standard"},bodyPreview:{type:"text"},date:{type:"date"},receivedAt:{type:"date"},hasAttachments:{type:"boolean"},attachmentNames:{type:"keyword"},labels:{type:"keyword"},folder:{type:"keyword"},threadId:{type:"keyword"},isRead:{type:"boolean"},isStarred:{type:"boolean"},mailbox:{type:"keyword"}}},settings:{number_of_shards:1,number_of_replicas:0}}}static buildSearchQuery(e){let n=[],r=[];if(e.query)n.push({multi_match:{query:e.query,fields:["subject^3","body","fromName","toName"],type:"best_fields",fuzziness:"AUTO"}});if(e.from)r.push({term:{from:e.from}});if(e.to)r.push({term:{to:e.to}});if(e.subject)n.push({match_phrase:{subject:e.subject}});if(e.hasAttachments!==void 0)r.push({term:{hasAttachments:e.hasAttachments}});if(e.folder)r.push({term:{folder:e.folder}});if(e.labels&&e.labels.length>0)r.push({terms:{labels:e.labels}});if(e.isRead!==void 0)r.push({term:{isRead:e.isRead}});if(e.dateFrom||e.dateTo){let a={date:{}};if(e.dateFrom)a.date.gte=e.dateFrom;if(e.dateTo)a.date.lte=e.dateTo;r.push({range:a})}let i={bool:{}};if(n.length>0)i.bool.must=n;if(r.length>0)i.bool.filter=r;if(n.length===0&&r.length===0)i.bool.must=[{match_all:{}}];let s=[];if(e.sort==="relevance"&&e.query)s.push({_score:e.sortOrder||"desc"});return s.push({date:e.sortOrder||"desc"}),{query:i,sort:s,from:e.offset||0,size:e.limit||20,highlight:{fields:{subject:{},body:{fragment_size:150,number_of_fragments:3}}}}}}class Vt{static ThreadingLambdaCode=`
|
|
3872
3870
|
const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
3873
3871
|
const crypto = require('crypto');
|
|
3874
3872
|
|
|
@@ -4008,7 +4006,7 @@ catch {
|
|
|
4008
4006
|
ContentType: 'application/json',
|
|
4009
4007
|
}));
|
|
4010
4008
|
}
|
|
4011
|
-
`;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:
|
|
4009
|
+
`;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:Vt.ThreadingLambdaCode},Environment:{Variables:{EMAIL_BUCKET:e.emailBucket}}}}}}static async getThreads(e){let{s3Client:n,bucket:r,mailbox:i,limit:s=50,offset:a=0}=e,[c,u]=i.includes("@")?i.split("@"):[i,"default"],d=`mailboxes/${u}/${c}/threads.json`;try{let m=await n.send({Bucket:r,Key:d}),p=JSON.parse(m.Body),g=Object.values(p);return g.sort((y,f)=>new Date(f.lastMessageDate).getTime()-new Date(y.lastMessageDate).getTime()),g.slice(a,a+s)}catch{return[]}}static async getThread(e){let{s3Client:n,bucket:r,mailbox:i,threadId:s}=e,[a,c]=i.includes("@")?i.split("@"):[i,"default"],u=`mailboxes/${c}/${a}/threads.json`;try{let d=await n.send({Bucket:r,Key:u});return JSON.parse(d.Body)[s]||null}catch{return null}}}class Ut{static SchedulerLambdaCode=`
|
|
4012
4010
|
const { S3Client, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, ListObjectsV2Command } = require('@aws-sdk/client-s3');
|
|
4013
4011
|
const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
|
|
4014
4012
|
|
|
@@ -4137,7 +4135,7 @@ else {
|
|
|
4137
4135
|
|
|
4138
4136
|
return raw;
|
|
4139
4137
|
}
|
|
4140
|
-
`;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
|
|
4138
|
+
`;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:Ut.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:n,bucket:r,email:i,scheduledFor:s,timezone:a}=e,c=`sched-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,u={id:c,email:i,scheduledFor:typeof s==="string"?s:s.toISOString(),timezone:a,status:"pending",createdAt:new Date().toISOString()};return await n.send({Bucket:r,Key:`scheduled/${c}.json`,Body:JSON.stringify(u,null,2),ContentType:"application/json"}),u}static async cancelScheduledEmail(e){let{s3Client:n,bucket:r,id:i}=e;try{let s=await n.send({Bucket:r,Key:`scheduled/${i}.json`}),a=JSON.parse(s.Body);if(a.status!=="pending")return!1;return a.status="cancelled",await n.send({Bucket:r,Key:`scheduled/${i}.json`,Body:JSON.stringify(a,null,2),ContentType:"application/json"}),!0}catch{return!1}}static async listScheduledEmails(e){let{s3Client:n,bucket:r,status:i}=e,s=await n.send({Bucket:r,Prefix:"scheduled/"}),a=[];for(let c of s.Contents||[]){if(!c.Key.endsWith(".json"))continue;try{let u=await n.send({Bucket:r,Key:c.Key}),d=JSON.parse(u.Body);if(!i||d.status===i)a.push(d)}catch{}}return a.sort((c,u)=>new Date(c.scheduledFor).getTime()-new Date(u.scheduledFor).getTime()),a}}class Ze{static TrackingPixelLambdaCode=`
|
|
4141
4139
|
const { DynamoDBClient, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
4142
4140
|
|
|
4143
4141
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -4340,7 +4338,7 @@ catch (error) {
|
|
|
4340
4338
|
|
|
4341
4339
|
return { statusCode: 200 };
|
|
4342
4340
|
};
|
|
4343
|
-
`;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:
|
|
4341
|
+
`;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:Ze.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:Ze.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:Ze.SesEventProcessorCode},Environment:{Variables:{ANALYTICS_TABLE:e.analyticsTable}}}}}}static injectTracking(e){let{html:n,messageId:r,trackingDomain:i}=e,s=`<img src="https://${i}/track/open/${r}" width="1" height="1" style="display:none" alt="" />`,a=n.replace("</body>",`${s}</body>`);return a=a.replace(/href="(https?:\/\/[^"]+)"/g,(c,u)=>{let d=encodeURIComponent(u);return`href="https://${i}/track/click/${r}?url=${d}"`}),a}static calculateMetrics(e){let n=e.filter((d)=>d.sent).length,r=e.filter((d)=>d.delivered).length,i=e.filter((d)=>d.opened).length,s=e.filter((d)=>d.clicked).length,a=e.filter((d)=>d.bounced).length,c=e.filter((d)=>d.complained).length,u=e.filter((d)=>d.unsubscribed).length;return{period:new Date().toISOString(),sent:n,delivered:r,opened:i,clicked:s,bounced:a,complained:c,unsubscribed:u,deliveryRate:n>0?r/n*100:0,openRate:r>0?i/r*100:0,clickRate:i>0?s/i*100:0,bounceRate:n>0?a/n*100:0,complaintRate:r>0?c/r*100:0}}}class Ae{static TemplateRendererCode=`
|
|
4344
4342
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
4345
4343
|
|
|
4346
4344
|
const s3 = new S3Client({});
|
|
@@ -4595,7 +4593,7 @@ The {{appName}} Team`,variables:["appName","userName","resetUrl","expiresIn"],ca
|
|
|
4595
4593
|
|
|
4596
4594
|
<p>Best regards,<br>The {{appName}} Team</p>
|
|
4597
4595
|
</body>
|
|
4598
|
-
</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:
|
|
4596
|
+
</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:Ae.TemplateRendererCode},Environment:{Variables:{TEMPLATE_BUCKET:e.templateBucket}}}}}}static render(e,n){if(!e||!n)return e;let r=e;return r=r.replace(/\{\{\s*([\w.]+)\s*\}\}/g,(i,s)=>{let a=Ae.getNestedValue(n,s);return a!==void 0?String(a):i}),r=r.replace(/\{\{#if\s+([\w.]+)\}\}([\s\S]*?)\{\{\/if\}\}/g,(i,s,a)=>Ae.getNestedValue(n,s)?a:""),r=r.replace(/\{\{#unless\s+([\w.]+)\}\}([\s\S]*?)\{\{\/unless\}\}/g,(i,s,a)=>!Ae.getNestedValue(n,s)?a:""),r=r.replace(/\{\{#each\s+([\w.]+)\}\}([\s\S]*?)\{\{\/each\}\}/g,(i,s,a)=>{let c=Ae.getNestedValue(n,s);if(!Array.isArray(c))return"";return c.map((u,d)=>{let m=a;if(m=m.replace(/\{\{this\}\}/g,String(u)),m=m.replace(/\{\{@index\}\}/g,String(d)),typeof u==="object")Object.entries(u).forEach(([p,g])=>{m=m.replace(new RegExp(`\\{\\{\\s*${p}\\s*\\}\\}`,"g"),String(g))});return m}).join("")}),r}static getNestedValue(e,n){return n.split(".").reduce((r,i)=>r?.[i],e)}static extractVariables(e){let n=new Set,r=e.matchAll(/\{\{\s*([\w.]+)\s*\}\}/g);for(let s of r)if(!s[1].startsWith("#")&&!s[1].startsWith("/")&&!s[1].startsWith("@"))n.add(s[1].split(".")[0]);let i=e.matchAll(/\{\{#(?:if|unless|each)\s+([\w.]+)\}\}/g);for(let s of i)n.add(s[1].split(".")[0]);return Array.from(n)}}class Ht{static SharedMailboxLambdaCode=`
|
|
4599
4597
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
4600
4598
|
const { DynamoDBClient, GetItemCommand, PutItemCommand, QueryCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
4601
4599
|
|
|
@@ -4826,7 +4824,7 @@ function unmarshallMailbox(item) {
|
|
|
4826
4824
|
updatedAt: item.updatedAt.S,
|
|
4827
4825
|
};
|
|
4828
4826
|
}
|
|
4829
|
-
`;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:
|
|
4827
|
+
`;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:Ht.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 jt{static RuleProcessorCode=`
|
|
4830
4828
|
const { S3Client, GetObjectCommand, PutObjectCommand, CopyObjectCommand, DeleteObjectCommand } = require('@aws-sdk/client-s3');
|
|
4831
4829
|
const { DynamoDBClient, QueryCommand } = require('@aws-sdk/client-dynamodb');
|
|
4832
4830
|
const { LambdaClient, InvokeCommand } = require('@aws-sdk/client-lambda');
|
|
@@ -5139,7 +5137,7 @@ async function invokeLambda(functionName, metadata) {
|
|
|
5139
5137
|
Payload: JSON.stringify(metadata),
|
|
5140
5138
|
}));
|
|
5141
5139
|
}
|
|
5142
|
-
`;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:
|
|
5140
|
+
`;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:jt.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 qs=`
|
|
5143
5141
|
const { S3Client, GetObjectCommand, PutObjectCommand, CopyObjectCommand } = require('@aws-sdk/client-s3');
|
|
5144
5142
|
const s3 = new S3Client({});
|
|
5145
5143
|
|
|
@@ -5297,7 +5295,7 @@ catch (error) {
|
|
|
5297
5295
|
|
|
5298
5296
|
return { statusCode: 200, body: 'OK' };
|
|
5299
5297
|
};
|
|
5300
|
-
`,
|
|
5298
|
+
`,zs=`
|
|
5301
5299
|
const { S3Client, GetObjectCommand, PutObjectCommand, CopyObjectCommand } = require('@aws-sdk/client-s3');
|
|
5302
5300
|
const s3 = new S3Client({});
|
|
5303
5301
|
|
|
@@ -5455,7 +5453,7 @@ catch (error) {
|
|
|
5455
5453
|
|
|
5456
5454
|
return { statusCode: 200, body: 'OK' };
|
|
5457
5455
|
};
|
|
5458
|
-
`;class
|
|
5456
|
+
`;class Kt{static RecordingProcessorCode=`
|
|
5459
5457
|
const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
|
|
5460
5458
|
const { TranscribeClient, StartTranscriptionJobCommand } = require('@aws-sdk/client-transcribe');
|
|
5461
5459
|
const { DynamoDBClient, PutItemCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
@@ -5647,7 +5645,7 @@ else if (jobStatus === 'FAILED') {
|
|
|
5647
5645
|
|
|
5648
5646
|
return { statusCode: 200 };
|
|
5649
5647
|
};
|
|
5650
|
-
`;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:
|
|
5648
|
+
`;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:Kt.RecordingProcessorCode},Environment:{Variables:{RECORDING_BUCKET:e.recordingBucket,RECORDINGS_TABLE:e.recordingsTable}}}}}}}class we{nodes=[];connections=[];startNodeId="";static create(e){return new we}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,n){let r={id:this.generateId(),type:"play-prompt",position:{x:0,y:0},config:{text:e,textType:n?.ssml?"ssml":"text",voice:n?.voice||"Joanna"}};return this.nodes.push(r),this.connectToLast(r.id),this}getInput(e,n){let r={id:this.generateId(),type:"get-input",position:{x:0,y:0},config:{prompt:e,maxDigits:n?.maxDigits||1,timeout:n?.timeout||5,errorPrompt:n?.errorPrompt||"Sorry, I didn't get that."}};return this.nodes.push(r),this.connectToLast(r.id),this}menu(e,n){let r={id:this.generateId(),type:"menu",position:{x:0,y:0},config:{prompt:e,options:n}};return this.nodes.push(r),this.connectToLast(r.id),this}transferToQueue(e,n){let r={id:this.generateId(),type:"transfer-queue",position:{x:0,y:0},config:{queueArn:e,priority:n?.priority||5}};return this.nodes.push(r),this.connectToLast(r.id),this}transferToPhone(e){let n={id:this.generateId(),type:"transfer-phone",position:{x:0,y:0},config:{phoneNumber:e}};return this.nodes.push(n),this.connectToLast(n.id),this}invokeLambda(e,n){let r={id:this.generateId(),type:"invoke-lambda",position:{x:0,y:0},config:{functionArn:e,timeout:n?.timeout||8}};return this.nodes.push(r),this.connectToLast(r.id),this}setAttribute(e,n){let r={id:this.generateId(),type:"set-attribute",position:{x:0,y:0},config:{key:e,value:n}};return this.nodes.push(r),this.connectToLast(r.id),this}checkHours(e){let n={id:this.generateId(),type:"check-hours",position:{x:0,y:0},config:{hoursOfOperationArn:e}};return this.nodes.push(n),this.connectToLast(n.id),this}recordVoicemail(e){let n={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(n),this.connectToLast(n.id),this}wait(e){let n={id:this.generateId(),type:"wait",position:{x:0,y:0},config:{seconds:e}};return this.nodes.push(n),this.connectToLast(n.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=[],n=new Map(this.nodes.map((i)=>[i.id,i]));for(let i of this.nodes){let s=this.nodeToAction(i,n);if(s)e.push(s)}let r={Version:"2019-10-30",StartAction:this.startNodeId,Actions:e};return JSON.stringify(r,null,2)}nodeToAction(e,n){let r=this.getNextNodeId(e.id),i={NextAction:r||"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:i};case"get-input":return{Identifier:e.id,Type:"GetParticipantInput",Parameters:{Text:e.config.prompt,InputTimeLimitSeconds:e.config.timeout,MaxDigits:e.config.maxDigits},Transitions:{...i,Conditions:[]}};case"transfer-queue":return{Identifier:e.id,Type:"TransferToQueue",Parameters:{QueueId:e.config.queueArn},Transitions:i};case"transfer-phone":return{Identifier:e.id,Type:"TransferToPhoneNumber",Parameters:{PhoneNumber:e.config.phoneNumber},Transitions:i};case"invoke-lambda":return{Identifier:e.id,Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:e.config.functionArn,InvocationTimeLimitSeconds:e.config.timeout},Transitions:i};case"set-attribute":return{Identifier:e.id,Type:"UpdateContactAttributes",Parameters:{Attributes:{[e.config.key]:e.config.value}},Transitions:i};case"check-hours":return{Identifier:e.id,Type:"CheckHoursOfOperation",Parameters:{HoursOfOperationId:e.config.hoursOfOperationArn},Transitions:{NextAction:r,Conditions:[{NextAction:r,Condition:{Operator:"Equals",Operands:["True"]}}],Errors:[{NextAction:"disconnect"}]}};case"wait":return{Identifier:e.id,Type:"Wait",Parameters:{Seconds:e.config.seconds},Transitions:i};case"disconnect":return{Identifier:e.id,Type:"DisconnectParticipant",Parameters:{},Transitions:{}};default:return null}}connectToLast(e){if(this.nodes.length>1){let n=this.nodes[this.nodes.length-2];this.connections.push({id:this.generateId(),sourceNodeId:n.id,targetNodeId:e,sourcePort:"default"})}}getNextNodeId(e){return this.connections.find((r)=>r.sourceNodeId===e)?.targetNodeId||null}generateId(){return`node-${Date.now()}-${Math.random().toString(36).substr(2,9)}`}static Templates={basicSupport:()=>we.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)=>we.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)=>we.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 qt{static MetricsAggregatorCode=`
|
|
5651
5649
|
const { DynamoDBClient, PutItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
|
|
5652
5650
|
|
|
5653
5651
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -5846,7 +5844,7 @@ catch (error) {
|
|
|
5846
5844
|
};
|
|
5847
5845
|
}
|
|
5848
5846
|
};
|
|
5849
|
-
`;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:
|
|
5847
|
+
`;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:qt.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 ot{static CallbackRequestCode=`
|
|
5850
5848
|
const { DynamoDBClient, PutItemCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
5851
5849
|
const { ConnectClient, StartOutboundVoiceContactCommand } = require('@aws-sdk/client-connect');
|
|
5852
5850
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
@@ -6136,7 +6134,7 @@ catch (error) {
|
|
|
6136
6134
|
return { statusCode: 500, error: error.message };
|
|
6137
6135
|
}
|
|
6138
6136
|
};
|
|
6139
|
-
`;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:
|
|
6137
|
+
`;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:ot.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:ot.CallbackProcessorCode},Environment:{Variables:{CALLBACKS_TABLE:e.callbacksTable,CONNECT_INSTANCE_ID:e.connectInstanceId,CONTACT_FLOW_ID:e.contactFlowId,SOURCE_PHONE_NUMBER:e.sourcePhoneNumber,QUEUE_ID:e.queueId||""}}}}}}}class zt{static CampaignManagerCode=`
|
|
6140
6138
|
const { DynamoDBClient, PutItemCommand, GetItemCommand, UpdateItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
|
|
6141
6139
|
|
|
6142
6140
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -6520,7 +6518,7 @@ function unmarshallCampaign(item) {
|
|
|
6520
6518
|
stats: JSON.parse(item.stats?.S || '{}'),
|
|
6521
6519
|
};
|
|
6522
6520
|
}
|
|
6523
|
-
`;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:
|
|
6521
|
+
`;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:zt.CampaignManagerCode},Environment:{Variables:{CAMPAIGNS_TABLE:e.campaignsTable}}}}}}}class Qt{static AnalyticsAggregatorCode=`
|
|
6524
6522
|
const { DynamoDBClient, ScanCommand, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
6525
6523
|
|
|
6526
6524
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -6715,7 +6713,7 @@ catch (error) {
|
|
|
6715
6713
|
|
|
6716
6714
|
return { statusCode: 200 };
|
|
6717
6715
|
};
|
|
6718
|
-
`;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:
|
|
6716
|
+
`;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:Qt.AnalyticsAggregatorCode},Environment:{Variables:{MESSAGE_LOG_TABLE:e.messageLogTable,ANALYTICS_TABLE:e.analyticsTable}}}}}}}class Jt{static MmsSenderCode=`
|
|
6719
6717
|
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
6720
6718
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
6721
6719
|
const { DynamoDBClient, PutItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
@@ -6907,8 +6905,8 @@ async function sendFallbackSms(to, message) {
|
|
|
6907
6905
|
fallback: true,
|
|
6908
6906
|
};
|
|
6909
6907
|
}
|
|
6910
|
-
`;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:
|
|
6911
|
-
`);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:
|
|
6908
|
+
`;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:Jt.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 Yt{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(`
|
|
6909
|
+
`);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:Yt.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 Xt{static LinkShortenerCode=`
|
|
6912
6910
|
const { DynamoDBClient, PutItemCommand, GetItemCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
6913
6911
|
const crypto = require('crypto');
|
|
6914
6912
|
|
|
@@ -7042,7 +7040,7 @@ function generateShortId() {
|
|
|
7042
7040
|
}
|
|
7043
7041
|
return id;
|
|
7044
7042
|
}
|
|
7045
|
-
`;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:
|
|
7043
|
+
`;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:Xt.LinkShortenerCode},Environment:{Variables:{LINKS_TABLE:e.linksTable,SHORT_DOMAIN:e.shortDomain||""}}}}}}static shortenUrlsInMessage(e,n,r){let i=/(https?:\/\/[^\s]+)/g,s=[],a=0;return{message:e.replace(i,(u)=>{let d=`${r}-${a++}`,m=`https://${n}/l/${d}`;return s.push({original:u,short:m,id:d}),m}),links:s}}}class pe{static AbTestManagerCode=`
|
|
7046
7044
|
const { DynamoDBClient, PutItemCommand, GetItemCommand, UpdateItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
|
|
7047
7045
|
|
|
7048
7046
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -7236,7 +7234,7 @@ function unmarshallTest(item) {
|
|
|
7236
7234
|
|
|
7237
7235
|
return test;
|
|
7238
7236
|
}
|
|
7239
|
-
`;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:me.AbTestManagerCode},Environment:{Variables:{AB_TESTS_TABLE:e.abTestsTable}}}}}}static selectVariant(e,n){let i=me.hashString(n+e.id)%100,s=0;for(let a=0;a<e.variants.length;a++)if(s+=e.trafficSplit[a],i<s)return e.variants[a];return e.variants[e.variants.length-1]}static determineWinner(e){if(e.variants.length===0)return null;let n=e.winningCriteria,r=e.variants[0],i=me.getMetricValue(r,n);for(let s of e.variants.slice(1)){let a=me.getMetricValue(s,n);if(a>i)i=a,r=s}return r}static calculateSignificance(e,n,r){let i=e.stats.sent,s=n.stats.sent;if(i<30||s<30)return 0;let a=me.getMetricValue(e,r)/100,c=me.getMetricValue(n,r)/100,u=(a*i+c*s)/(i+s),d=Math.sqrt(u*(1-u)*(1/i+1/s));if(d===0)return 0;let m=Math.abs(a-c)/d;if(m>=2.576)return 99;if(m>=1.96)return 95;if(m>=1.645)return 90;if(m>=1.28)return 80;return Math.round(m*30)}static getMetricValue(e,n){switch(n){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 n=0;for(let r=0;r<e.length;r++){let i=e.charCodeAt(r);n=(n<<5)-n+i,n=n&n}return Math.abs(n)}}class cd{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 n=`fifo-queue-${Date.now()}-${this.queueCounter++}`,r=e.name.endsWith(".fifo")?e.name:`${e.name}.fifo`,{name:i,...s}=e,a={id:n,name:r,queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${r}`,...s};return this.queues.set(n,a),this.createDeduplicationConfig({queueId:n,contentBasedDeduplication:e.contentBasedDeduplication,deduplicationInterval:300}),a}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 r={id:`dedup-${Date.now()}-${this.deduplicationCounter++}`,deduplicationHashes:new Map,...e};return this.deduplicationConfigs.set(e.queueId,r),r}sendMessage(e){let n=this.queues.get(e.queueId);if(!n)throw Error(`Queue not found: ${e.queueId}`);let r=this.deduplicationConfigs.get(e.queueId);if(r){let c=e.messageDeduplicationId||(n.contentBasedDeduplication?this.generateHash(e.messageBody):void 0);if(c&&this.isDuplicate(r,c))return null;if(c)r.deduplicationHashes.set(c,new Date)}let i=`msg-${Date.now()}-${this.messageCounter++}`,s=this.generateSequenceNumber(),a={id:i,messageId:i,messageGroupId:e.messageGroupId,messageDeduplicationId:e.messageDeduplicationId,body:e.messageBody,attributes:e.messageAttributes||{},sentTimestamp:new Date,sequenceNumber:s};return this.messages.set(i,a),this.updateMessageGroup(e.queueId,e.messageGroupId),a}isDuplicate(e,n){let r=e.deduplicationHashes.get(n);if(!r)return!1;if((Date.now()-r.getTime())/1000>e.deduplicationInterval)return e.deduplicationHashes.delete(n),!1;return!0}generateHash(e){let n=0;for(let r=0;r<e.length;r++){let i=e.charCodeAt(r);n=(n<<5)-n+i,n=n&n}return Math.abs(n).toString(36)}generateSequenceNumber(){return`${Date.now()}${this.sequenceCounter++}`.padStart(20,"0")}updateMessageGroup(e,n){let r=`${e}-${n}`,i=this.messageGroups.get(r);if(!i)i={id:`group-${Date.now()}-${this.groupCounter++}`,messageGroupId:n,queueId:e,messagesInFlight:0},this.messageGroups.set(r,i);i.messagesInFlight++,i.lastMessageTimestamp=new Date}getMessageGroups(e){return Array.from(this.messageGroups.values()).filter((n)=>n.queueId===e)}getQueue(e){return this.queues.get(e)}listQueues(){return Array.from(this.queues.values())}getMessages(e,n){let r=Array.from(this.messages.values());if(n)r=r.filter((i)=>i.messageGroupId===n);return r.sort((i,s)=>i.sequenceNumber.localeCompare(s.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 ch=new cd;class ld{monitors=new Map;metrics=new Map;alerts=new Map;reprocessJobs=new Map;monitorCounter=0;metricsCounter=0;alertCounter=0;jobCounter=0;createDLQMonitor(e){let n=`dlq-monitor-${Date.now()}-${this.monitorCounter++}`,r={id:n,...e};return this.monitors.set(n,r),r}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 r={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)},i=this.metrics.get(e)||[];return i.push(r),this.metrics.set(e,i),this.checkForAlerts(e,r),r}checkForAlerts(e,n){let r=Array.from(this.monitors.values()).find((s)=>s.queueUrl===e);if(!r)return;if(n.approximateNumberOfMessages>=r.alarmThreshold)this.createAlert({monitorId:r.id,alertType:"threshold_exceeded",severity:"high",message:`DLQ ${r.name} has ${n.approximateNumberOfMessages} messages (threshold: ${r.alarmThreshold})`});let i=3600;if(n.approximateAgeOfOldestMessage>i)this.createAlert({monitorId:r.id,alertType:"old_message",severity:"medium",message:`DLQ ${r.name} has messages older than ${i} seconds`})}createAlert(e){let n=`alert-${Date.now()}-${this.alertCounter++}`,r={id:n,timestamp:new Date,acknowledged:!1,...e};return this.alerts.set(n,r),r}acknowledgeAlert(e){let n=this.alerts.get(e);if(!n)throw Error(`Alert not found: ${e}`);return n.acknowledged=!0,n}createReprocessJob(e){let n=`reprocess-${Date.now()}-${this.jobCounter++}`,r={id:n,queueUrl:e.queueUrl,messageId:e.messageId,attempts:0,status:"pending"};return this.reprocessJobs.set(n,r),r}async executeReprocessJob(e){let n=this.reprocessJobs.get(e);if(!n)throw Error(`Reprocess job not found: ${e}`);n.status="processing",n.startedAt=new Date,n.attempts++,await new Promise((i)=>setTimeout(i,100));let r=Math.random()>0.3;if(n.status=r?"success":"failed",n.completedAt=new Date,!r)n.error="Reprocessing failed - original error still present";return n}async batchReprocess(e){let n=[];for(let r=0;r<e.maxMessages;r++){let i=this.createReprocessJob({queueUrl:e.queueUrl,messageId:`msg-${r}`});await this.executeReprocessJob(i.id),n.push(i)}return n}getDLQStatistics(e,n=24){let r=new Date(Date.now()-n*60*60*1000),i=(this.metrics.get(e)||[]).filter((p)=>p.timestamp>=r);if(i.length===0)return{totalMessages:0,avgAge:0,messagesReceived:0,messagesDeleted:0,messagesReprocessed:0,successRate:0};let s=i[i.length-1],a=i.reduce((p,g)=>p+g.messagesReceived,0),c=i.reduce((p,g)=>p+g.messagesDeleted,0),u=i.reduce((p,g)=>p+g.messagesReprocessed,0),d=i.reduce((p,g)=>p+g.approximateAgeOfOldestMessage,0)/i.length,m=u>0?c/u*100:0;return{totalMessages:s.approximateNumberOfMessages,avgAge:d,messagesReceived:a,messagesDeleted:c,messagesReprocessed:u,successRate:m}}getMonitor(e){return this.monitors.get(e)}listMonitors(){return Array.from(this.monitors.values())}getAlerts(e,n){let r=Array.from(this.alerts.values());if(e)r=r.filter((i)=>i.monitorId===e);if(n!==void 0)r=r.filter((i)=>i.acknowledged===n);return r.sort((i,s)=>s.timestamp.getTime()-i.timestamp.getTime())}getReprocessJobs(e){let n=Array.from(this.reprocessJobs.values());if(e)n=n.filter((r)=>r.queueUrl===e);return n}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 lh=new ld;class dd{configs=new Map;jobs=new Map;metrics=new Map;configCounter=0;jobCounter=0;metricsCounter=0;createBatchConfig(e){let n=`batch-config-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.configs.set(n,r),r}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 n=`batch-job-${Date.now()}-${this.jobCounter++}`;if(!this.configs.get(e.configId))throw Error(`Batch config not found: ${e.configId}`);let i=[];for(let a=0;a<e.messageCount;a++)i.push({id:`msg-${n}-${a}`,messageId:`${n}-${a}`,body:`Message ${a}`,receiptHandle:`receipt-${n}-${a}`,attributes:{},status:"pending"});let s={id:n,configId:e.configId,messages:i,status:"pending",processedCount:0,failedCount:0};return this.jobs.set(n,s),s}async processBatchJob(e){let n=this.jobs.get(e);if(!n)throw Error(`Batch job not found: ${e}`);let r=this.configs.get(n.configId);if(!r)throw Error(`Batch config not found: ${n.configId}`);n.status="processing",n.startedAt=new Date;let i=this.chunkArray(n.messages,r.batchSize);for(let s of i)await this.processBatch(s,r);return n.processedCount=n.messages.filter((s)=>s.status==="success").length,n.failedCount=n.messages.filter((s)=>s.status==="failed").length,n.status=n.failedCount===0?"completed":"failed",n.completedAt=new Date,this.collectProcessorMetrics(r.id,n),n}async processBatch(e,n){let r=e.map((i)=>this.processMessage(i,n));await Promise.all(r)}async processMessage(e,n){e.status="processing";let r=Date.now();await new Promise((a)=>setTimeout(a,Math.random()*100));let i=Date.now()-r;if(e.processingTime=i,Math.random()>0.1)e.status="success";else e.status="failed",e.error="Processing error"}chunkArray(e,n){let r=[];for(let i=0;i<e.length;i+=n)r.push(e.slice(i,i+n));return r}collectProcessorMetrics(e,n){let r=`metrics-${Date.now()}-${this.metricsCounter++}`,s=n.messages.filter((g)=>g.status==="success").map((g)=>g.processingTime||0).filter((g)=>g>0),a=s.length>0?s.reduce((g,y)=>g+y,0)/s.length:0,c=n.completedAt&&n.startedAt?(n.completedAt.getTime()-n.startedAt.getTime())/1000:1,u=n.processedCount/c,d=n.messages.length>0?n.failedCount/n.messages.length*100:0,m={id:r,configId:e,timestamp:new Date,messagesProcessed:n.processedCount,averageProcessingTime:a,throughput:u,errorRate:d},p=this.metrics.get(e)||[];p.push(m),this.metrics.set(e,p)}getBatchStatistics(e){let n=this.metrics.get(e)||[];if(n.length===0)return{totalJobsProcessed:0,totalMessagesProcessed:0,averageThroughput:0,averageErrorRate:0,averageProcessingTime:0};let r=n.reduce((c,u)=>c+u.messagesProcessed,0),i=n.reduce((c,u)=>c+u.throughput,0)/n.length,s=n.reduce((c,u)=>c+u.errorRate,0)/n.length,a=n.reduce((c,u)=>c+u.averageProcessingTime,0)/n.length;return{totalJobsProcessed:n.length,totalMessagesProcessed:r,averageThroughput:i,averageErrorRate:s,averageProcessingTime:a}}optimizeBatchConfig(e){let n=this.configs.get(e);if(!n)throw Error(`Batch config not found: ${e}`);let r=this.getBatchStatistics(e);if(r.averageErrorRate<5&&n.batchSize<10)n.batchSize=Math.min(10,n.batchSize+1);if(r.averageErrorRate>20&&n.batchSize>1)n.batchSize=Math.max(1,n.batchSize-1);if(r.averageThroughput<5&&n.parallelProcessors<20)n.parallelProcessors++;return n}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getJob(e){return this.jobs.get(e)}listJobs(e){let n=Array.from(this.jobs.values());if(e)n=n.filter((r)=>r.configId===e);return n}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 dh=new dd;class ud{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 n=`queue-${Date.now()}-${this.queueCounter++}`,r={id:n,purgeInProgress:!1,...e};return this.queues.set(n,r),r}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 n=`retention-${Date.now()}-${this.retentionCounter++}`,r={id:n,...e};this.retentionPolicies.set(n,r);let i=this.queues.get(e.queueId);if(i)i.messageRetentionPeriod=e.retentionPeriod;return r}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 n=`delay-${Date.now()}-${this.delayCounter++}`,r={id:n,...e};this.delayQueues.set(n,r);let i=Array.from(this.queues.values()).find((s)=>s.queueUrl===e.queueUrl);if(i)i.delaySeconds=e.defaultDelay;return r}createScheduledDelayQueue(e){return this.createDelayQueue({queueUrl:e.queueUrl,defaultDelay:e.delayMinutes*60,perMessageDelay:!1,maxDelay:900})}async purgeQueue(e){let n=this.queues.get(e);if(!n)throw Error(`Queue not found: ${e}`);if(n.purgeInProgress)throw Error("Purge already in progress for this queue");let r=`purge-${Date.now()}-${this.purgeCounter++}`,i={id:r,queueUrl:n.queueUrl,status:"in_progress",startedAt:new Date};return this.purgeOperations.set(r,i),n.purgeInProgress=!0,setTimeout(()=>{i.status="completed",i.completedAt=new Date,i.messagesPurged=Math.floor(Math.random()*1000),n.purgeInProgress=!1},100),i}collectQueueMetrics(e){let r={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)},i=this.metrics.get(e)||[];return i.push(r),this.metrics.set(e,i),r}getQueueHealth(e){let n=this.metrics.get(e)||[];if(n.length===0)return{status:"healthy",issues:[],recommendations:[]};let r=n[n.length-1],i=[],s=[],a="healthy";if(r.approximateNumberOfMessages>1e4)a="critical",i.push("Large message backlog detected"),s.push("Increase consumer capacity");else if(r.approximateNumberOfMessages>1000)a="warning",i.push("Growing message backlog"),s.push("Monitor consumer performance");if(r.oldestMessageAge&&r.oldestMessageAge>3600){if(a!=="critical")a="warning";i.push("Old messages in queue"),s.push("Review message processing")}if(r.approximateNumberOfMessagesDelayed>100){if(a!=="critical")a="warning";i.push("High number of delayed messages")}return{status:a,issues:i,recommendations:s}}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 n=Array.from(this.purgeOperations.values());if(e)n=n.filter((r)=>r.queueUrl===e);return n}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 uh=new ud;import{deflateRawSync as gs}from"node:zlib";var ys=(()=>{let e=[];for(let n=0;n<256;n++){let r=n;for(let i=0;i<8;i++)r=r&1?3988292384^r>>>1:r>>>1;e[n]=r>>>0}return e})();function fs(e){let n=4294967295;for(let r=0;r<e.length;r++)n=ys[(n^e[r])&255]^n>>>8;return(n^4294967295)>>>0}function hs(e){if(typeof e==="string")return Buffer.from(e,"utf-8");if(Buffer.isBuffer(e))return e;return Buffer.from(e)}function bs(e){let n=Math.max(1980,e.getFullYear()),r=(e.getHours()<<11|e.getMinutes()<<5|e.getSeconds()>>1)&65535,i=(n-1980<<9|e.getMonth()+1<<5|e.getDate())&65535;return{time:r,date:i}}function _t(e){let n=[],r=[],i=0;for(let c of e){let u=hs(c.data),d=gs(u),m=fs(u),p=Buffer.from(c.name.replace(/\\/g,"/"),"utf-8"),{time:g,date:y}=bs(c.date??new Date(0)),f=c.mode??420,h=Buffer.alloc(30+p.length);h.writeUInt32LE(67324752,0),h.writeUInt16LE(20,4),h.writeUInt16LE(0,6),h.writeUInt16LE(8,8),h.writeUInt16LE(g,10),h.writeUInt16LE(y,12),h.writeUInt32LE(m,14),h.writeUInt32LE(d.length,18),h.writeUInt32LE(u.length,22),h.writeUInt16LE(p.length,26),h.writeUInt16LE(0,28),p.copy(h,30);let S=Buffer.alloc(46+p.length);S.writeUInt32LE(33639248,0),S.writeUInt16LE(798,4),S.writeUInt16LE(20,6),S.writeUInt16LE(0,8),S.writeUInt16LE(8,10),S.writeUInt16LE(g,12),S.writeUInt16LE(y,14),S.writeUInt32LE(m,16),S.writeUInt32LE(d.length,20),S.writeUInt32LE(u.length,24),S.writeUInt16LE(p.length,28),S.writeUInt16LE(0,30),S.writeUInt16LE(0,32),S.writeUInt16LE(0,34),S.writeUInt16LE(0,36),S.writeUInt32LE((f&65535)<<16,38),S.writeUInt32LE(i,42),p.copy(S,46),n.push(h,d),r.push(S),i+=h.length+d.length}let s=Buffer.concat(r),a=Buffer.alloc(22);return a.writeUInt32LE(101010256,0),a.writeUInt16LE(0,4),a.writeUInt16LE(0,6),a.writeUInt16LE(e.length,8),a.writeUInt16LE(e.length,10),a.writeUInt32LE(s.length,12),a.writeUInt32LE(i,16),a.writeUInt16LE(0,20),Buffer.concat([...n,s,a])}function pd(e){let n=e.adapterImport??"./adapter",r=e.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
|
|
7237
|
+
`;static createAbTestsTable(e){return{[`${e.slug}AbTestsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e.slug}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createAbTestManagerLambda(e){return{[`${e.slug}AbTestManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e.slug}-ab-test-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:e.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:pe.AbTestManagerCode},Environment:{Variables:{AB_TESTS_TABLE:e.abTestsTable}}}}}}static selectVariant(e,n){let i=pe.hashString(n+e.id)%100,s=0;for(let a=0;a<e.variants.length;a++)if(s+=e.trafficSplit[a],i<s)return e.variants[a];return e.variants[e.variants.length-1]}static determineWinner(e){if(e.variants.length===0)return null;let n=e.winningCriteria,r=e.variants[0],i=pe.getMetricValue(r,n);for(let s of e.variants.slice(1)){let a=pe.getMetricValue(s,n);if(a>i)i=a,r=s}return r}static calculateSignificance(e,n,r){let i=e.stats.sent,s=n.stats.sent;if(i<30||s<30)return 0;let a=pe.getMetricValue(e,r)/100,c=pe.getMetricValue(n,r)/100,u=(a*i+c*s)/(i+s),d=Math.sqrt(u*(1-u)*(1/i+1/s));if(d===0)return 0;let m=Math.abs(a-c)/d;if(m>=2.576)return 99;if(m>=1.96)return 95;if(m>=1.645)return 90;if(m>=1.28)return 80;return Math.round(m*30)}static getMetricValue(e,n){switch(n){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 n=0;for(let r=0;r<e.length;r++){let i=e.charCodeAt(r);n=(n<<5)-n+i,n=n&n}return Math.abs(n)}}class bd{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 n=`fifo-queue-${Date.now()}-${this.queueCounter++}`,r=e.name.endsWith(".fifo")?e.name:`${e.name}.fifo`,{name:i,...s}=e,a={id:n,name:r,queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${r}`,...s};return this.queues.set(n,a),this.createDeduplicationConfig({queueId:n,contentBasedDeduplication:e.contentBasedDeduplication,deduplicationInterval:300}),a}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 r={id:`dedup-${Date.now()}-${this.deduplicationCounter++}`,deduplicationHashes:new Map,...e};return this.deduplicationConfigs.set(e.queueId,r),r}sendMessage(e){let n=this.queues.get(e.queueId);if(!n)throw Error(`Queue not found: ${e.queueId}`);let r=this.deduplicationConfigs.get(e.queueId);if(r){let c=e.messageDeduplicationId||(n.contentBasedDeduplication?this.generateHash(e.messageBody):void 0);if(c&&this.isDuplicate(r,c))return null;if(c)r.deduplicationHashes.set(c,new Date)}let i=`msg-${Date.now()}-${this.messageCounter++}`,s=this.generateSequenceNumber(),a={id:i,messageId:i,messageGroupId:e.messageGroupId,messageDeduplicationId:e.messageDeduplicationId,body:e.messageBody,attributes:e.messageAttributes||{},sentTimestamp:new Date,sequenceNumber:s};return this.messages.set(i,a),this.updateMessageGroup(e.queueId,e.messageGroupId),a}isDuplicate(e,n){let r=e.deduplicationHashes.get(n);if(!r)return!1;if((Date.now()-r.getTime())/1000>e.deduplicationInterval)return e.deduplicationHashes.delete(n),!1;return!0}generateHash(e){let n=0;for(let r=0;r<e.length;r++){let i=e.charCodeAt(r);n=(n<<5)-n+i,n=n&n}return Math.abs(n).toString(36)}generateSequenceNumber(){return`${Date.now()}${this.sequenceCounter++}`.padStart(20,"0")}updateMessageGroup(e,n){let r=`${e}-${n}`,i=this.messageGroups.get(r);if(!i)i={id:`group-${Date.now()}-${this.groupCounter++}`,messageGroupId:n,queueId:e,messagesInFlight:0},this.messageGroups.set(r,i);i.messagesInFlight++,i.lastMessageTimestamp=new Date}getMessageGroups(e){return Array.from(this.messageGroups.values()).filter((n)=>n.queueId===e)}getQueue(e){return this.queues.get(e)}listQueues(){return Array.from(this.queues.values())}getMessages(e,n){let r=Array.from(this.messages.values());if(n)r=r.filter((i)=>i.messageGroupId===n);return r.sort((i,s)=>i.sequenceNumber.localeCompare(s.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 Ch=new bd;class Sd{monitors=new Map;metrics=new Map;alerts=new Map;reprocessJobs=new Map;monitorCounter=0;metricsCounter=0;alertCounter=0;jobCounter=0;createDLQMonitor(e){let n=`dlq-monitor-${Date.now()}-${this.monitorCounter++}`,r={id:n,...e};return this.monitors.set(n,r),r}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 r={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)},i=this.metrics.get(e)||[];return i.push(r),this.metrics.set(e,i),this.checkForAlerts(e,r),r}checkForAlerts(e,n){let r=Array.from(this.monitors.values()).find((s)=>s.queueUrl===e);if(!r)return;if(n.approximateNumberOfMessages>=r.alarmThreshold)this.createAlert({monitorId:r.id,alertType:"threshold_exceeded",severity:"high",message:`DLQ ${r.name} has ${n.approximateNumberOfMessages} messages (threshold: ${r.alarmThreshold})`});let i=3600;if(n.approximateAgeOfOldestMessage>i)this.createAlert({monitorId:r.id,alertType:"old_message",severity:"medium",message:`DLQ ${r.name} has messages older than ${i} seconds`})}createAlert(e){let n=`alert-${Date.now()}-${this.alertCounter++}`,r={id:n,timestamp:new Date,acknowledged:!1,...e};return this.alerts.set(n,r),r}acknowledgeAlert(e){let n=this.alerts.get(e);if(!n)throw Error(`Alert not found: ${e}`);return n.acknowledged=!0,n}createReprocessJob(e){let n=`reprocess-${Date.now()}-${this.jobCounter++}`,r={id:n,queueUrl:e.queueUrl,messageId:e.messageId,attempts:0,status:"pending"};return this.reprocessJobs.set(n,r),r}async executeReprocessJob(e){let n=this.reprocessJobs.get(e);if(!n)throw Error(`Reprocess job not found: ${e}`);n.status="processing",n.startedAt=new Date,n.attempts++,await new Promise((i)=>setTimeout(i,100));let r=Math.random()>0.3;if(n.status=r?"success":"failed",n.completedAt=new Date,!r)n.error="Reprocessing failed - original error still present";return n}async batchReprocess(e){let n=[];for(let r=0;r<e.maxMessages;r++){let i=this.createReprocessJob({queueUrl:e.queueUrl,messageId:`msg-${r}`});await this.executeReprocessJob(i.id),n.push(i)}return n}getDLQStatistics(e,n=24){let r=new Date(Date.now()-n*60*60*1000),i=(this.metrics.get(e)||[]).filter((p)=>p.timestamp>=r);if(i.length===0)return{totalMessages:0,avgAge:0,messagesReceived:0,messagesDeleted:0,messagesReprocessed:0,successRate:0};let s=i[i.length-1],a=i.reduce((p,g)=>p+g.messagesReceived,0),c=i.reduce((p,g)=>p+g.messagesDeleted,0),u=i.reduce((p,g)=>p+g.messagesReprocessed,0),d=i.reduce((p,g)=>p+g.approximateAgeOfOldestMessage,0)/i.length,m=u>0?c/u*100:0;return{totalMessages:s.approximateNumberOfMessages,avgAge:d,messagesReceived:a,messagesDeleted:c,messagesReprocessed:u,successRate:m}}getMonitor(e){return this.monitors.get(e)}listMonitors(){return Array.from(this.monitors.values())}getAlerts(e,n){let r=Array.from(this.alerts.values());if(e)r=r.filter((i)=>i.monitorId===e);if(n!==void 0)r=r.filter((i)=>i.acknowledged===n);return r.sort((i,s)=>s.timestamp.getTime()-i.timestamp.getTime())}getReprocessJobs(e){let n=Array.from(this.reprocessJobs.values());if(e)n=n.filter((r)=>r.queueUrl===e);return n}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 Th=new Sd;class vd{configs=new Map;jobs=new Map;metrics=new Map;configCounter=0;jobCounter=0;metricsCounter=0;createBatchConfig(e){let n=`batch-config-${Date.now()}-${this.configCounter++}`,r={id:n,...e};return this.configs.set(n,r),r}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 n=`batch-job-${Date.now()}-${this.jobCounter++}`;if(!this.configs.get(e.configId))throw Error(`Batch config not found: ${e.configId}`);let i=[];for(let a=0;a<e.messageCount;a++)i.push({id:`msg-${n}-${a}`,messageId:`${n}-${a}`,body:`Message ${a}`,receiptHandle:`receipt-${n}-${a}`,attributes:{},status:"pending"});let s={id:n,configId:e.configId,messages:i,status:"pending",processedCount:0,failedCount:0};return this.jobs.set(n,s),s}async processBatchJob(e){let n=this.jobs.get(e);if(!n)throw Error(`Batch job not found: ${e}`);let r=this.configs.get(n.configId);if(!r)throw Error(`Batch config not found: ${n.configId}`);n.status="processing",n.startedAt=new Date;let i=this.chunkArray(n.messages,r.batchSize);for(let s of i)await this.processBatch(s,r);return n.processedCount=n.messages.filter((s)=>s.status==="success").length,n.failedCount=n.messages.filter((s)=>s.status==="failed").length,n.status=n.failedCount===0?"completed":"failed",n.completedAt=new Date,this.collectProcessorMetrics(r.id,n),n}async processBatch(e,n){let r=e.map((i)=>this.processMessage(i,n));await Promise.all(r)}async processMessage(e,n){e.status="processing";let r=Date.now();await new Promise((a)=>setTimeout(a,Math.random()*100));let i=Date.now()-r;if(e.processingTime=i,Math.random()>0.1)e.status="success";else e.status="failed",e.error="Processing error"}chunkArray(e,n){let r=[];for(let i=0;i<e.length;i+=n)r.push(e.slice(i,i+n));return r}collectProcessorMetrics(e,n){let r=`metrics-${Date.now()}-${this.metricsCounter++}`,s=n.messages.filter((g)=>g.status==="success").map((g)=>g.processingTime||0).filter((g)=>g>0),a=s.length>0?s.reduce((g,y)=>g+y,0)/s.length:0,c=n.completedAt&&n.startedAt?(n.completedAt.getTime()-n.startedAt.getTime())/1000:1,u=n.processedCount/c,d=n.messages.length>0?n.failedCount/n.messages.length*100:0,m={id:r,configId:e,timestamp:new Date,messagesProcessed:n.processedCount,averageProcessingTime:a,throughput:u,errorRate:d},p=this.metrics.get(e)||[];p.push(m),this.metrics.set(e,p)}getBatchStatistics(e){let n=this.metrics.get(e)||[];if(n.length===0)return{totalJobsProcessed:0,totalMessagesProcessed:0,averageThroughput:0,averageErrorRate:0,averageProcessingTime:0};let r=n.reduce((c,u)=>c+u.messagesProcessed,0),i=n.reduce((c,u)=>c+u.throughput,0)/n.length,s=n.reduce((c,u)=>c+u.errorRate,0)/n.length,a=n.reduce((c,u)=>c+u.averageProcessingTime,0)/n.length;return{totalJobsProcessed:n.length,totalMessagesProcessed:r,averageThroughput:i,averageErrorRate:s,averageProcessingTime:a}}optimizeBatchConfig(e){let n=this.configs.get(e);if(!n)throw Error(`Batch config not found: ${e}`);let r=this.getBatchStatistics(e);if(r.averageErrorRate<5&&n.batchSize<10)n.batchSize=Math.min(10,n.batchSize+1);if(r.averageErrorRate>20&&n.batchSize>1)n.batchSize=Math.max(1,n.batchSize-1);if(r.averageThroughput<5&&n.parallelProcessors<20)n.parallelProcessors++;return n}getConfig(e){return this.configs.get(e)}listConfigs(){return Array.from(this.configs.values())}getJob(e){return this.jobs.get(e)}listJobs(e){let n=Array.from(this.jobs.values());if(e)n=n.filter((r)=>r.configId===e);return n}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 Eh=new vd;class Cd{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 n=`queue-${Date.now()}-${this.queueCounter++}`,r={id:n,purgeInProgress:!1,...e};return this.queues.set(n,r),r}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 n=`retention-${Date.now()}-${this.retentionCounter++}`,r={id:n,...e};this.retentionPolicies.set(n,r);let i=this.queues.get(e.queueId);if(i)i.messageRetentionPeriod=e.retentionPeriod;return r}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 n=`delay-${Date.now()}-${this.delayCounter++}`,r={id:n,...e};this.delayQueues.set(n,r);let i=Array.from(this.queues.values()).find((s)=>s.queueUrl===e.queueUrl);if(i)i.delaySeconds=e.defaultDelay;return r}createScheduledDelayQueue(e){return this.createDelayQueue({queueUrl:e.queueUrl,defaultDelay:e.delayMinutes*60,perMessageDelay:!1,maxDelay:900})}async purgeQueue(e){let n=this.queues.get(e);if(!n)throw Error(`Queue not found: ${e}`);if(n.purgeInProgress)throw Error("Purge already in progress for this queue");let r=`purge-${Date.now()}-${this.purgeCounter++}`,i={id:r,queueUrl:n.queueUrl,status:"in_progress",startedAt:new Date};return this.purgeOperations.set(r,i),n.purgeInProgress=!0,setTimeout(()=>{i.status="completed",i.completedAt=new Date,i.messagesPurged=Math.floor(Math.random()*1000),n.purgeInProgress=!1},100),i}collectQueueMetrics(e){let r={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)},i=this.metrics.get(e)||[];return i.push(r),this.metrics.set(e,i),r}getQueueHealth(e){let n=this.metrics.get(e)||[];if(n.length===0)return{status:"healthy",issues:[],recommendations:[]};let r=n[n.length-1],i=[],s=[],a="healthy";if(r.approximateNumberOfMessages>1e4)a="critical",i.push("Large message backlog detected"),s.push("Increase consumer capacity");else if(r.approximateNumberOfMessages>1000)a="warning",i.push("Growing message backlog"),s.push("Monitor consumer performance");if(r.oldestMessageAge&&r.oldestMessageAge>3600){if(a!=="critical")a="warning";i.push("Old messages in queue"),s.push("Review message processing")}if(r.approximateNumberOfMessagesDelayed>100){if(a!=="critical")a="warning";i.push("High number of delayed messages")}return{status:a,issues:i,recommendations:s}}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 n=Array.from(this.purgeOperations.values());if(e)n=n.filter((r)=>r.queueUrl===e);return n}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 wh=new Cd;import{deflateRawSync as Qs}from"node:zlib";var Js=(()=>{let e=[];for(let n=0;n<256;n++){let r=n;for(let i=0;i<8;i++)r=r&1?3988292384^r>>>1:r>>>1;e[n]=r>>>0}return e})();function Ys(e){let n=4294967295;for(let r=0;r<e.length;r++)n=Js[(n^e[r])&255]^n>>>8;return(n^4294967295)>>>0}function Zs(e){if(typeof e==="string")return Buffer.from(e,"utf-8");if(Buffer.isBuffer(e))return e;return Buffer.from(e)}function Xs(e){let n=Math.max(1980,e.getFullYear()),r=(e.getHours()<<11|e.getMinutes()<<5|e.getSeconds()>>1)&65535,i=(n-1980<<9|e.getMonth()+1<<5|e.getDate())&65535;return{time:r,date:i}}function $t(e){let n=[],r=[],i=0;for(let c of e){let u=Zs(c.data),d=Qs(u),m=Ys(u),p=Buffer.from(c.name.replace(/\\/g,"/"),"utf-8"),{time:g,date:y}=Xs(c.date??new Date(0)),f=c.mode??420,h=Buffer.alloc(30+p.length);h.writeUInt32LE(67324752,0),h.writeUInt16LE(20,4),h.writeUInt16LE(0,6),h.writeUInt16LE(8,8),h.writeUInt16LE(g,10),h.writeUInt16LE(y,12),h.writeUInt32LE(m,14),h.writeUInt32LE(d.length,18),h.writeUInt32LE(u.length,22),h.writeUInt16LE(p.length,26),h.writeUInt16LE(0,28),p.copy(h,30);let S=Buffer.alloc(46+p.length);S.writeUInt32LE(33639248,0),S.writeUInt16LE(798,4),S.writeUInt16LE(20,6),S.writeUInt16LE(0,8),S.writeUInt16LE(8,10),S.writeUInt16LE(g,12),S.writeUInt16LE(y,14),S.writeUInt32LE(m,16),S.writeUInt32LE(d.length,20),S.writeUInt32LE(u.length,24),S.writeUInt16LE(p.length,28),S.writeUInt16LE(0,30),S.writeUInt16LE(0,32),S.writeUInt16LE(0,34),S.writeUInt16LE(0,36),S.writeUInt32LE((f&65535)<<16,38),S.writeUInt32LE(i,42),p.copy(S,46),n.push(h,d),r.push(S),i+=h.length+d.length}let s=Buffer.concat(r),a=Buffer.alloc(22);return a.writeUInt32LE(101010256,0),a.writeUInt16LE(0,4),a.writeUInt16LE(0,6),a.writeUInt16LE(e.length,8),a.writeUInt16LE(e.length,10),a.writeUInt32LE(s.length,12),a.writeUInt32LE(i,16),a.writeUInt16LE(0,20),Buffer.concat([...n,s,a])}function Td(e){let n=e.adapterImport??"./adapter",r=e.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
|
|
7240
7238
|
import * as __userModule from ${JSON.stringify(r)}
|
|
7241
7239
|
import { resolveApp, createHandlers } from ${JSON.stringify(n)}
|
|
7242
7240
|
|
|
@@ -7246,9 +7244,9 @@ const __handlers = createHandlers(__app)
|
|
|
7246
7244
|
export const http = __handlers.http
|
|
7247
7245
|
export const queue = __handlers.queue
|
|
7248
7246
|
export const cli = __handlers.cli
|
|
7249
|
-
`}import{execSync as
|
|
7247
|
+
`}import{execSync as ea}from"node:child_process";import{createHash as ta}from"node:crypto";import{cpSync as na,mkdtempSync as ra,rmSync as ia,writeFileSync as sa}from"node:fs";import{tmpdir as aa}from"node:os";import{dirname as oa,isAbsolute as ca,join as Oe,resolve as la}from"node:path";import{fileURLToPath as ua}from"node:url";var da=["adapter.ts","recursion.ts","auto-recursion.ts"];function ma(){return Oe(oa(ua(import.meta.url)),"runtime")}function xp(e,n,r){for(let i of e??[])r?.(`build: ${i}`),ea(i,{stdio:"inherit",cwd:n})}function ms(e){return ta("sha256").update(e).digest("hex")}function oc(e,n,r){return`deployments/${e}/${n}/${r}.zip`}async function xn(e){let n=la(e.projectRoot??process.cwd()),{app:r}=e;if(!e.skipBuild)xp(r.build,n,e.onStep);let i=r.entry;if(!i)throw Error("serverless app: `entry` is required to package a Node/Bun application");let s=ca(i)?i:Oe(n,i),a=ra(Oe(aa(),"tscloud-pkg-"));try{for(let y of da)na(Oe(ma(),y),Oe(a,y));let c=Oe(a,"bootstrap.ts");sa(c,Td({entryImport:s,adapterImport:"./adapter"})),e.onStep?.("bundling application");let u=await Bun.build({entrypoints:[c],target:r.kind==="bun"?"bun":"node",format:"esm",minify:!1,sourcemap:"none"});if(!u.success){let y=u.logs.map((f)=>String(f)).join(`
|
|
7250
7248
|
`);throw Error(`serverless app bundle failed:
|
|
7251
|
-
${y}`)}let d=u.outputs[0],m=Buffer.from(await d.arrayBuffer()),p="index",g=_t([{name:`${p}.mjs`,data:m}]);return{zip:g,bundle:m,sha256:os(g),handlerFile:p,handlers:{http:r.handlers?.http??`${p}.http`,queue:r.handlers?.queue??`${p}.queue`,cli:r.handlers?.cli??`${p}.cli`},bundleBytes:m.length}}finally{Ts(a,{recursive:!0,force:!0})}}var Cp=["18","20","22"];function ks(e){if(!e)return"22";let n=String(e).match(/(\d+)/);return n?n[1]:"22"}function Ji(e){let n=e.kind??"node";if(n==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(n==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let r=ks(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&Cp.includes(r))return{lambdaRuntime:e.runtime&&e.runtime.startsWith("nodejs")?e.runtime:`nodejs${r}.x`,kind:"node",version:r,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:r,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function rr(e,n,r){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${n}-${r}-default`}];return e.queues.map((i)=>{if(typeof i==="string")return{name:`${n}-${r}-${i}`};let[s,a]=Object.entries(i)[0];return{name:`${n}-${r}-${s}`,concurrency:a}})}function Ya(e,n,r){return rr(e,n,r).map((i)=>i.name)}function Za(e){let{app:n,environment:r,handlers:i}=e,s=e.config.project.slug,a=Ji(n).lambdaRuntime,c=n.architecture??"x86_64",u=e.config.project.region,d={http:`${s}-${r}-http`,queue:`${s}-${r}-queue`,cli:`${s}-${r}-cli`};if(n.gatewayVersion===1)throw Error("serverless app: `gatewayVersion: 1` (REST API) is not supported — ts-cloud uses API Gateway HTTP API (v2). Remove `gatewayVersion` or set it to 2.");let m=rr(n,s,r),p=m.map((k)=>k.name),g=p.length>0,y=n.logRetention??14,f=n.packaging==="image";if(f&&n.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=(n.scheduler??"on")!=="off",S=(n.cache?.driver??"dynamodb")==="dynamodb",A=Boolean(n.assets),R=Fi(s,r),P=n.tmpStorage??512,C={},E={},D=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:t.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:t.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${s}-${r}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${s}/${r}/*`),t.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${s}/${r}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[t.sub(`arn:aws:s3:::${R}`),t.sub(`arn:aws:s3:::${R}/*`),...n.storage?.bucket?[t.sub(`arn:aws:s3:::${n.storage.bucket}`),t.sub(`arn:aws:s3:::${n.storage.bucket}/*`)]:[]]}]}}];if(g)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:t.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${s}-${r}-*`)});if(S)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${s}-${r}-cache*`)});let x=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(n.vpc?.subnets?.length)x.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(n.lambdaInsights)x.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");C.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${s}-${r}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:x,Policies:D}};let L=(k)=>({TSCLOUD_LAMBDA_MODE:k,TSCLOUD_ENV:r,...n.octane?{TSCLOUD_OCTANE:"1"}:{},...n.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...S?{TSCLOUD_CACHE_TABLE:`${s}-${r}-cache`}:{},...g?{TSCLOUD_QUEUE:p[0]}:{},...n.env??{}}),B=Boolean(n.efs),O=typeof n.efs==="object"?n.efs:{},F=O.mountPath??"/mnt/local",V=B&&!O.accessPointArn,ce=O.accessPointArn??(V?t.getAtt("EfsAccessPoint","Arn"):void 0),q=n.vpc?.subnets??[],J=q.length>0,K=n.cache?.driver==="elasticache"||n.database?.connection==="aurora-serverless"||Boolean(n.rdsProxy)||B;if(K&&!J)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let z=J?{VpcConfig:{SubnetIds:q,SecurityGroupIds:[...n.vpc?.securityGroups??[],...K?[t.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},ge=V?q.map((k,G)=>`EfsMountTarget${G}`):[],Te=B?{FileSystemConfigs:[{Arn:ce,LocalMountPath:F}]}:{};if(B)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function ne(k,G,W,_,te,mt,Be,he=P){C[`${k}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${G}`,RetentionInDays:y}};let Fe=[...e.runtimeLayers??[],...n.lambdaInsights?[n.lambdaInsights.layerArn]:[]],Xt=f?{PackageType:"Image",Code:{ImageUri:t.ref("ImageUri")},...n.kind==="php"?{}:{ImageConfig:{Command:[W]}}}:{Runtime:a,Handler:W,Code:{S3Bucket:t.ref("ArtifactBucket"),S3Key:t.ref("ArtifactKey")},...Fe.length?{Layers:[...new Set(Fe)]}:{}};C[k]={Type:"AWS::Lambda::Function",DependsOn:[`${k}LogGroup`,...ge],Properties:{FunctionName:G,Architectures:[c],MemorySize:te,Timeout:mt,Role:t.getAtt("AppRole","Arn"),Environment:{Variables:L(_)},EphemeralStorage:{Size:he},...Xt,...Be!==void 0?{ReservedConcurrentExecutions:Be}:{},...z,...Te}}}if(ne("HttpFunction",d.http,i.http,"http",n.memory??1024,n.timeout??28,n.concurrency,P),ne("CliFunction",d.cli,i.cli,"cli",n.cliMemory??1024,n.cliTimeout??900,void 0,n.cliTmpStorage??P),g)ne("QueueFunction",d.queue,i.queue,"queue",n.queueMemory??1024,n.queueTimeout??120,void 0,n.queueTmpStorage??P);let ee=(n.provisionedConcurrency??0)>0?n.provisionedConcurrency:0,re=["HttpFunction","CliFunction",...g?["QueueFunction"]:[]];if(ee)for(let k of re)C[`${k}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:t.ref(k)}},C[`${k}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:t.ref(k),Name:"live",FunctionVersion:t.getAtt(`${k}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:ee}}};let fe=(k)=>ee?t.ref(`${k}Alias`):t.getAtt(k,"Arn"),ie=(k)=>ee?t.ref(`${k}Alias`):t.ref(k);C.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${s}-${r}`,ProtocolType:"HTTP"}},C.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:t.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:fe("HttpFunction"),PayloadFormatVersion:"2.0"}},C.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:t.ref("HttpApi"),RouteKey:"$default",Target:t.join("/",["integrations",t.ref("HttpIntegration")])}},C.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},C.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ie("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},E.HttpApiEndpoint={Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint")},E.HttpApiId={Description:"HTTP API id",Value:t.ref("HttpApi")};let le=(Array.isArray(n.domain)?n.domain:n.domain?[n.domain]:[]).filter(Boolean);if(le.length){if(!n.certificateArn&&!n.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let k=n.certificateArn;if(!k)C.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:le[0],...le.length>1?{SubjectAlternativeNames:le.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:le.map((G)=>({DomainName:G,HostedZoneId:n.hostedZoneId}))}},k=t.ref("HttpCertificate");le.forEach((G,W)=>{let _=`HttpDomain${W}`;if(C[_]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:G,DomainNameConfigurations:[{CertificateArn:k,EndpointType:"REGIONAL"}]}},C[`HttpApiMapping${W}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:t.ref("HttpApi"),DomainName:t.ref(_),Stage:"$default"}},n.hostedZoneId)C[`HttpDomainRecord${W}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:G,Type:"A",AliasTarget:{DNSName:t.getAtt(_,"RegionalDomainName"),HostedZoneId:t.getAtt(_,"RegionalHostedZoneId")}}};E[`CustomDomain${W}`]={Description:`Custom domain ${G}`,Value:G},E[`CustomDomainTarget${W}`]={Description:`Point ${G} (CNAME/alias) at this APIGW regional domain`,Value:t.getAtt(_,"RegionalDomainName")}})}if(g)C.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${s}-${r}-dlq`,MessageRetentionPeriod:1209600}},m.forEach((k,G)=>{let W=`AppQueue${G}`,_=n.queueTimeout??120;C[W]={Type:"AWS::SQS::Queue",Properties:{QueueName:k.name,VisibilityTimeout:Math.min(43200,_*6),RedrivePolicy:{deadLetterTargetArn:t.getAtt("AppQueueDlq","Arn"),maxReceiveCount:n.queueTries??3}}};let te=k.concurrency??n.queueConcurrency;C[`${W}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:t.getAtt(W,"Arn"),FunctionName:ie("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...te?{ScalingConfig:{MaximumConcurrency:Math.max(2,te)}}:{}}},E[`QueueUrl${G}`]={Description:`Queue URL: ${k.name}`,Value:t.ref(W)}});if(h)C.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${s}-${r}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:fe("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},C.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ie("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.getAtt("SchedulerRule","Arn")}};if(n.warm&&n.warm>0){let G={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},W=(n.warmFunctions??["http"]).filter((_)=>_!=="queue"||g);for(let _ of W){let te=_.charAt(0).toUpperCase()+_.slice(1),mt=Math.ceil(n.warm/5),Be=0;for(let he=0;he<mt;he++){let Fe=Math.min(5,n.warm-Be);C[`Warmer${te}Rule${he}`]={Type:"AWS::Events::Rule",Properties:{Name:`${s}-${r}-warmer-${_}-${he}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Fe},(Xt,lr)=>({Id:`warm-${_}-${he}-${lr}`,Arn:t.getAtt(G[_],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Be+=Fe}C[`Warmer${te}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:t.ref(G[_]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${s}-${r}-warmer-${_}-*`)}}}}if(S)C.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-${r}-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:t.ref("CacheTable")};if(A){if(C.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:R,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},C.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${s}-${r}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},C.AssetsDistribution={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,DefaultCacheBehavior:{TargetOriginId:"assets",ViewerProtocolPolicy:"redirect-to-https",Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},Origins:[{Id:"assets",DomainName:t.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:t.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...n.assetDomain?{Aliases:[n.assetDomain],ViewerCertificate:{AcmCertificateArn:n.assetCertificateArn??t.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},n.assetDomain){if(!n.assetCertificateArn){if(!n.hostedZoneId)throw Error("serverless app: `assetDomain` requires either `assetCertificateArn` (a us-east-1 ACM cert) or `hostedZoneId` (to auto-issue + validate one). CloudFront only accepts certs from us-east-1.");if(u!=="us-east-1")throw Error(`serverless app: auto-issuing an asset-domain cert needs a us-east-1 app (CloudFront certs must be us-east-1); this app is in ${u}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);C.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:n.assetDomain,HostedZoneId:n.hostedZoneId}]}}}if(n.hostedZoneId)C.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:n.assetDomain,Type:"A",AliasTarget:{DNSName:t.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};E.AssetDomain={Description:"Custom asset CDN host",Value:n.assetDomain}}C.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:t.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:t.sub(`arn:aws:s3:::${R}/*`),Condition:{StringEquals:{"AWS:SourceArn":t.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},E.AssetsBucketName={Description:"Assets bucket",Value:t.ref("AssetsBucket")},E.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:t.getAtt("AssetsDistribution","DomainName")}}if(n.firewall?.enabled){let k=[],G=0;if(n.firewall.rateLimit)k.push({Name:"rate-limit",Priority:G++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:n.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-${r}-rate`}});let W={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let _ of n.firewall.rules??[]){let te=W[_];if(!te)continue;k.push({Name:`managed-${_}`,Priority:G++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:te}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-${r}-${_}`}})}C.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${s}-${r}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:k,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-${r}-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:t.getAtt("WebAcl","Arn")}}if(J&&K){if(!n.vpc?.id)throw Error("serverless app: data services (elasticache / aurora-serverless / rdsProxy / efs) need app.vpc.id (the VPC id) so the managed security group is created in the right VPC.");C.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:n.vpc.id,GroupDescription:`${s}-${r} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(V)C.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${s}-${r}-efs`}]}},q.forEach((k,G)=>{C[`EfsMountTarget${G}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:t.ref("EfsFileSystem"),SubnetId:k,SecurityGroups:[t.getAtt("DataSecurityGroup","GroupId")]}}}),C.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:t.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},E.EfsFileSystemId={Description:"EFS file system id",Value:t.ref("EfsFileSystem")};if(n.cache?.driver==="elasticache")C.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${s}-${r} cache subnets`,SubnetIds:q}},C.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${s}-${r}-cache`,ReplicationGroupDescription:`${s}-${r} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},E.CacheEndpoint={Description:"Redis primary endpoint",Value:t.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(n.database?.connection==="aurora-serverless")C.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${s}-${r} db subnets`,SubnetIds:q}},C.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${s}/${r}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},C.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${s}-${r}-db`,DatabaseName:"app",MasterUsername:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:n.database?.minCapacity??0.5,MaxCapacity:n.database?.maxCapacity??4},DBSubnetGroupName:t.ref("DbSubnetGroup"),VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")]}},C.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:t.ref("DbCluster")}},E.DbEndpoint={Description:"Aurora cluster endpoint",Value:t.getAtt("DbCluster","Endpoint.Address")};if(n.rdsProxy&&n.database?.connection==="aurora-serverless")C.DbProxyRole={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"read-db-secret",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:t.ref("DbSecret")}]}}]}},C.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof n.rdsProxy==="object"&&n.rdsProxy.name?n.rdsProxy.name:`${s}-${r}-proxy`,EngineFamily:"MYSQL",RoleArn:t.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:t.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:q,VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},C.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:t.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[t.ref("DbCluster")]}},E.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:t.getAtt("DbProxy","Endpoint")};if(E.HttpFunctionName={Description:"HTTP function name",Value:t.ref("HttpFunction")},E.CliFunctionName={Description:"CLI function name",Value:t.ref("CliFunction")},g)E.QueueFunctionName={Description:"Queue function name",Value:t.ref("QueueFunction")};let Ee={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${s}-${r})`,Parameters:f?{ImageUri:{Type:"String",Description:"ECR image URI of the deployment artifact"}}:{ArtifactBucket:{Type:"String",Description:"S3 bucket holding the deployment artifact"},ArtifactKey:{Type:"String",Description:"S3 key of the deployment artifact (zip)"}},Resources:C,Outputs:E},Oe={};for(let k of Object.values(C))Oe[k.Type]=(Oe[k.Type]??0)+1;return{template:Ee,functionNames:d,queueNames:p,resourceSummary:Oe}}var Tp=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function Ep(e){let n=`php${e.replace(".","")}`;return Tp.map((r)=>`${n}-php-${r}`)}function ec(e,n){let r=`php${e.replace(".","")}`,i=Ep(e).join(" \\\n "),s=`/opt/remi/${r}/root`,a=`/etc/opt/remi/${r}`;return`${n?`FROM almalinux:9 AS ${n}`:"FROM almalinux:9"}
|
|
7249
|
+
${y}`)}let d=u.outputs[0],m=Buffer.from(await d.arrayBuffer()),p="index",g=$t([{name:`${p}.mjs`,data:m}]);return{zip:g,bundle:m,sha256:ms(g),handlerFile:p,handlers:{http:r.handlers?.http??`${p}.http`,queue:r.handlers?.queue??`${p}.queue`,cli:r.handlers?.cli??`${p}.cli`},bundleBytes:m.length}}finally{ia(a,{recursive:!0,force:!0})}}var _p=["18","20","22"];function pa(e){if(!e)return"22";let n=String(e).match(/(\d+)/);return n?n[1]:"22"}function eo(e){let n=e.kind??"node";if(n==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:e.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(n==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:e.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let r=pa(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&_p.includes(r))return{lambdaRuntime:e.runtime&&e.runtime.startsWith("nodejs")?e.runtime:`nodejs${r}.x`,kind:"node",version:r,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:r,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function ir(e,n,r){if(e.queues===!1)return[];if(e.queues===void 0||e.queues===!0)return[{name:`${n}-${r}-default`}];return e.queues.map((i)=>{if(typeof i==="string")return{name:`${n}-${r}-${i}`};let[s,a]=Object.entries(i)[0];return{name:`${n}-${r}-${s}`,concurrency:a}})}function sc(e,n,r){return ir(e,n,r).map((i)=>i.name)}function ac(e){let{app:n,environment:r,handlers:i}=e,s=e.config.project.slug,a=eo(n).lambdaRuntime,c=n.architecture??"x86_64",u=e.config.project.region,d={http:`${s}-${r}-http`,queue:`${s}-${r}-queue`,cli:`${s}-${r}-cli`};if(n.gatewayVersion===1)throw Error("serverless app: `gatewayVersion: 1` (REST API) is not supported — ts-cloud uses API Gateway HTTP API (v2). Remove `gatewayVersion` or set it to 2.");let m=ir(n,s,r),p=m.map((k)=>k.name),g=p.length>0,y=n.logRetention??14,f=n.packaging==="image";if(f&&n.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=(n.scheduler??"on")!=="off",S=(n.cache?.driver??"dynamodb")==="dynamodb",A=Boolean(n.assets),R=Vi(s,r),P=n.tmpStorage??512,C={},E={},D=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:t.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:t.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${s}-${r}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${s}/${r}/*`),t.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${s}/${r}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[t.sub(`arn:aws:s3:::${R}`),t.sub(`arn:aws:s3:::${R}/*`),...n.storage?.bucket?[t.sub(`arn:aws:s3:::${n.storage.bucket}`),t.sub(`arn:aws:s3:::${n.storage.bucket}/*`)]:[]]}]}}];if(g)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:t.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${s}-${r}-*`)});if(S)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:t.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${s}-${r}-cache*`)});let x=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(n.vpc?.subnets?.length)x.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(n.lambdaInsights)x.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");C.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${s}-${r}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:x,Policies:D}};let L=(k)=>({TSCLOUD_LAMBDA_MODE:k,TSCLOUD_ENV:r,...n.octane?{TSCLOUD_OCTANE:"1"}:{},...n.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...S?{TSCLOUD_CACHE_TABLE:`${s}-${r}-cache`}:{},...g?{TSCLOUD_QUEUE:p[0]}:{},...n.env??{}}),B=Boolean(n.efs),O=typeof n.efs==="object"?n.efs:{},F=O.mountPath??"/mnt/local",V=B&&!O.accessPointArn,le=O.accessPointArn??(V?t.getAtt("EfsAccessPoint","Arn"):void 0),q=n.vpc?.subnets??[],J=q.length>0,K=n.cache?.driver==="elasticache"||n.database?.connection==="aurora-serverless"||Boolean(n.rdsProxy)||B;if(K&&!J)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let z=J?{VpcConfig:{SubnetIds:q,SecurityGroupIds:[...n.vpc?.securityGroups??[],...K?[t.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},ye=V?q.map((k,G)=>`EfsMountTarget${G}`):[],Te=B?{FileSystemConfigs:[{Arn:le,LocalMountPath:F}]}:{};if(B)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function re(k,G,W,_,ne,yt,Fe,he=P){C[`${k}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${G}`,RetentionInDays:y}};let _e=[...e.runtimeLayers??[],...n.lambdaInsights?[n.lambdaInsights.layerArn]:[]],rn=f?{PackageType:"Image",Code:{ImageUri:t.ref("ImageUri")},...n.kind==="php"?{}:{ImageConfig:{Command:[W]}}}:{Runtime:a,Handler:W,Code:{S3Bucket:t.ref("ArtifactBucket"),S3Key:t.ref("ArtifactKey")},..._e.length?{Layers:[...new Set(_e)]}:{}};C[k]={Type:"AWS::Lambda::Function",DependsOn:[`${k}LogGroup`,...ye],Properties:{FunctionName:G,Architectures:[c],MemorySize:ne,Timeout:yt,Role:t.getAtt("AppRole","Arn"),Environment:{Variables:L(_)},EphemeralStorage:{Size:he},...rn,...Fe!==void 0?{ReservedConcurrentExecutions:Fe}:{},...z,...Te}}}if(re("HttpFunction",d.http,i.http,"http",n.memory??1024,n.timeout??28,n.concurrency,P),re("CliFunction",d.cli,i.cli,"cli",n.cliMemory??1024,n.cliTimeout??900,void 0,n.cliTmpStorage??P),g)re("QueueFunction",d.queue,i.queue,"queue",n.queueMemory??1024,n.queueTimeout??120,void 0,n.queueTmpStorage??P);let te=(n.provisionedConcurrency??0)>0?n.provisionedConcurrency:0,ie=["HttpFunction","CliFunction",...g?["QueueFunction"]:[]];if(te)for(let k of ie)C[`${k}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:t.ref(k)}},C[`${k}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:t.ref(k),Name:"live",FunctionVersion:t.getAtt(`${k}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:te}}};let fe=(k)=>te?t.ref(`${k}Alias`):t.getAtt(k,"Arn"),ae=(k)=>te?t.ref(`${k}Alias`):t.ref(k);C.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${s}-${r}`,ProtocolType:"HTTP"}},C.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:t.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:fe("HttpFunction"),PayloadFormatVersion:"2.0"}},C.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:t.ref("HttpApi"),RouteKey:"$default",Target:t.join("/",["integrations",t.ref("HttpIntegration")])}},C.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},C.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ae("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},E.HttpApiEndpoint={Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint")},E.HttpApiId={Description:"HTTP API id",Value:t.ref("HttpApi")};let de=(Array.isArray(n.domain)?n.domain:n.domain?[n.domain]:[]).filter(Boolean);if(de.length){if(!n.certificateArn&&!n.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let k=n.certificateArn;if(!k)C.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:de[0],...de.length>1?{SubjectAlternativeNames:de.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:de.map((G)=>({DomainName:G,HostedZoneId:n.hostedZoneId}))}},k=t.ref("HttpCertificate");de.forEach((G,W)=>{let _=`HttpDomain${W}`;if(C[_]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:G,DomainNameConfigurations:[{CertificateArn:k,EndpointType:"REGIONAL"}]}},C[`HttpApiMapping${W}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:t.ref("HttpApi"),DomainName:t.ref(_),Stage:"$default"}},n.hostedZoneId)C[`HttpDomainRecord${W}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:G,Type:"A",AliasTarget:{DNSName:t.getAtt(_,"RegionalDomainName"),HostedZoneId:t.getAtt(_,"RegionalHostedZoneId")}}};E[`CustomDomain${W}`]={Description:`Custom domain ${G}`,Value:G},E[`CustomDomainTarget${W}`]={Description:`Point ${G} (CNAME/alias) at this APIGW regional domain`,Value:t.getAtt(_,"RegionalDomainName")}})}if(g)C.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${s}-${r}-dlq`,MessageRetentionPeriod:1209600}},m.forEach((k,G)=>{let W=`AppQueue${G}`,_=n.queueTimeout??120;C[W]={Type:"AWS::SQS::Queue",Properties:{QueueName:k.name,VisibilityTimeout:Math.min(43200,_*6),RedrivePolicy:{deadLetterTargetArn:t.getAtt("AppQueueDlq","Arn"),maxReceiveCount:n.queueTries??3}}};let ne=k.concurrency??n.queueConcurrency;C[`${W}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:t.getAtt(W,"Arn"),FunctionName:ae("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...ne?{ScalingConfig:{MaximumConcurrency:Math.max(2,ne)}}:{}}},E[`QueueUrl${G}`]={Description:`Queue URL: ${k.name}`,Value:t.ref(W)}});if(h)C.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${s}-${r}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:fe("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},C.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ae("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.getAtt("SchedulerRule","Arn")}};if(n.warm&&n.warm>0){let G={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},W=(n.warmFunctions??["http"]).filter((_)=>_!=="queue"||g);for(let _ of W){let ne=_.charAt(0).toUpperCase()+_.slice(1),yt=Math.ceil(n.warm/5),Fe=0;for(let he=0;he<yt;he++){let _e=Math.min(5,n.warm-Fe);C[`Warmer${ne}Rule${he}`]={Type:"AWS::Events::Rule",Properties:{Name:`${s}-${r}-warmer-${_}-${he}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:_e},(rn,Tr)=>({Id:`warm-${_}-${he}-${Tr}`,Arn:t.getAtt(G[_],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Fe+=_e}C[`Warmer${ne}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:t.ref(G[_]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${s}-${r}-warmer-${_}-*`)}}}}if(S)C.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${s}-${r}-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:t.ref("CacheTable")};if(A){if(C.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:R,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},C.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${s}-${r}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},C.AssetsDistribution={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,DefaultCacheBehavior:{TargetOriginId:"assets",ViewerProtocolPolicy:"redirect-to-https",Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},Origins:[{Id:"assets",DomainName:t.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:t.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...n.assetDomain?{Aliases:[n.assetDomain],ViewerCertificate:{AcmCertificateArn:n.assetCertificateArn??t.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},n.assetDomain){if(!n.assetCertificateArn){if(!n.hostedZoneId)throw Error("serverless app: `assetDomain` requires either `assetCertificateArn` (a us-east-1 ACM cert) or `hostedZoneId` (to auto-issue + validate one). CloudFront only accepts certs from us-east-1.");if(u!=="us-east-1")throw Error(`serverless app: auto-issuing an asset-domain cert needs a us-east-1 app (CloudFront certs must be us-east-1); this app is in ${u}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);C.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:n.assetDomain,HostedZoneId:n.hostedZoneId}]}}}if(n.hostedZoneId)C.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:n.assetDomain,Type:"A",AliasTarget:{DNSName:t.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};E.AssetDomain={Description:"Custom asset CDN host",Value:n.assetDomain}}C.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:t.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:t.sub(`arn:aws:s3:::${R}/*`),Condition:{StringEquals:{"AWS:SourceArn":t.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},E.AssetsBucketName={Description:"Assets bucket",Value:t.ref("AssetsBucket")},E.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:t.getAtt("AssetsDistribution","DomainName")}}if(n.firewall?.enabled){let k=[],G=0;if(n.firewall.rateLimit)k.push({Name:"rate-limit",Priority:G++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:n.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-${r}-rate`}});let W={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let _ of n.firewall.rules??[]){let ne=W[_];if(!ne)continue;k.push({Name:`managed-${_}`,Priority:G++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:ne}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-${r}-${_}`}})}C.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${s}-${r}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:k,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-${r}-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:t.getAtt("WebAcl","Arn")}}if(J&&K){if(!n.vpc?.id)throw Error("serverless app: data services (elasticache / aurora-serverless / rdsProxy / efs) need app.vpc.id (the VPC id) so the managed security group is created in the right VPC.");C.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:n.vpc.id,GroupDescription:`${s}-${r} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(V)C.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${s}-${r}-efs`}]}},q.forEach((k,G)=>{C[`EfsMountTarget${G}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:t.ref("EfsFileSystem"),SubnetId:k,SecurityGroups:[t.getAtt("DataSecurityGroup","GroupId")]}}}),C.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:t.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},E.EfsFileSystemId={Description:"EFS file system id",Value:t.ref("EfsFileSystem")};if(n.cache?.driver==="elasticache")C.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${s}-${r} cache subnets`,SubnetIds:q}},C.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${s}-${r}-cache`,ReplicationGroupDescription:`${s}-${r} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},E.CacheEndpoint={Description:"Redis primary endpoint",Value:t.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(n.database?.connection==="aurora-serverless")C.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${s}-${r} db subnets`,SubnetIds:q}},C.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${s}/${r}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},C.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${s}-${r}-db`,DatabaseName:"app",MasterUsername:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:t.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:n.database?.minCapacity??0.5,MaxCapacity:n.database?.maxCapacity??4},DBSubnetGroupName:t.ref("DbSubnetGroup"),VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")]}},C.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:t.ref("DbCluster")}},E.DbEndpoint={Description:"Aurora cluster endpoint",Value:t.getAtt("DbCluster","Endpoint.Address")};if(n.rdsProxy&&n.database?.connection==="aurora-serverless")C.DbProxyRole={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"read-db-secret",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:t.ref("DbSecret")}]}}]}},C.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof n.rdsProxy==="object"&&n.rdsProxy.name?n.rdsProxy.name:`${s}-${r}-proxy`,EngineFamily:"MYSQL",RoleArn:t.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:t.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:q,VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},C.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:t.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[t.ref("DbCluster")]}},E.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:t.getAtt("DbProxy","Endpoint")};if(E.HttpFunctionName={Description:"HTTP function name",Value:t.ref("HttpFunction")},E.CliFunctionName={Description:"CLI function name",Value:t.ref("CliFunction")},g)E.QueueFunctionName={Description:"Queue function name",Value:t.ref("QueueFunction")};let Ee={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${s}-${r})`,Parameters:f?{ImageUri:{Type:"String",Description:"ECR image URI of the deployment artifact"}}:{ArtifactBucket:{Type:"String",Description:"S3 bucket holding the deployment artifact"},ArtifactKey:{Type:"String",Description:"S3 key of the deployment artifact (zip)"}},Resources:C,Outputs:E},Be={};for(let k of Object.values(C))Be[k.Type]=(Be[k.Type]??0)+1;return{template:Ee,functionNames:d,queueNames:p,resourceSummary:Be}}var Op=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function $p(e){let n=`php${e.replace(".","")}`;return Op.map((r)=>`${n}-php-${r}`)}function cc(e,n){let r=`php${e.replace(".","")}`,i=$p(e).join(" \\\n "),s=`/opt/remi/${r}/root`,a=`/etc/opt/remi/${r}`;return`${n?`FROM almalinux:9 AS ${n}`:"FROM almalinux:9"}
|
|
7252
7250
|
|
|
7253
7251
|
# Build PHP on AlmaLinux 9 (where Remi's version-isolated SCL packages install
|
|
7254
7252
|
# cleanly — Remi's release RPM rejects Amazon Linux 2023). AlmaLinux 9 shares
|
|
@@ -7288,9 +7286,9 @@ RUN printf 'extension_dir=/opt/php/lib/php/modules\\n' > /opt/php/etc/php.ini &&
|
|
|
7288
7286
|
# Runtime assets (bootstrap, runtime loops, fpm config) are added by the build
|
|
7289
7287
|
# orchestrator after the image is produced. Export /opt as the layer payload.
|
|
7290
7288
|
CMD ["true"]
|
|
7291
|
-
`}function
|
|
7292
|
-
${
|
|
7293
|
-
${
|
|
7289
|
+
`}function Ed(e={}){let n=e.phpVersion??"8.3";return`# ts-cloud PHP ${n} runtime layer (generated) — AWS Lambda provided.al2023.
|
|
7290
|
+
${cc(n)}`}function lc(e){if(e.kind==="php"){let r=e.phpVersion??"8.3";return`# ts-cloud serverless PHP app image (generated, multi-stage).
|
|
7291
|
+
${cc(r,"phpbuild")}
|
|
7294
7292
|
|
|
7295
7293
|
FROM public.ecr.aws/lambda/provided:al2023
|
|
7296
7294
|
# Bake the relocated PHP runtime from the build stage.
|
|
@@ -7309,7 +7307,7 @@ COPY app/ \${LAMBDA_TASK_ROOT}/
|
|
|
7309
7307
|
|
|
7310
7308
|
# Per-function CMD (e.g. index.http) is supplied via ImageConfig.Command.
|
|
7311
7309
|
CMD [ "index.http" ]
|
|
7312
|
-
`}import{execFileSync as ot}from"node:child_process";import{mkdtempSync as jn,readFileSync as lt,rmSync as Kn}from"node:fs";import{tmpdir as qn}from"node:os";import{dirname as Ms,join as pe}from"node:path";import{fileURLToPath as Ls}from"node:url";function zn(){return Ms(Ls(import.meta.url))}function gd(){return lt(pe(zn(),"runtime.mjs"),"utf-8")}function Qn(e){return lt(pe(zn(),`${e}-bootstrap`),"utf-8")}function ph(e){let n=e.architecture??"x86_64",r=n==="arm64"?"arm64":"x64",i=e.version.replace(/^v/,""),s=e.onStep??(()=>{}),a=jn(pe(qn(),"tscloud-node-layer-"));try{let c=i.includes(".")?i:Os(i),u=`node-v${c}-linux-${r}`,d=`https://nodejs.org/dist/v${c}/${u}.tar.xz`;s(`downloading Node ${c} (${n})`);let m=pe(a,"node.tar.xz");Jn(d,m),s("extracting node binary"),ot("tar",["-xf",m,"-C",a,`${u}/bin/node`],{stdio:"inherit"});let p=lt(pe(a,u,"bin","node"));s("packaging layer");let g=[{name:"bootstrap",data:Qn("node"),mode:493},{name:"runtime.mjs",data:gd(),mode:420},{name:"bin/node",data:p,mode:493}];return{zip:_t(g),architecture:n,version:c,fileCount:g.length}}finally{Kn(a,{recursive:!0,force:!0})}}function mh(e){let n=e.architecture??"x86_64",r=n==="arm64"?"bun-linux-aarch64":"bun-linux-x64",i=e.version==="latest"?"":e.version.replace(/^v/,""),s=e.onStep??(()=>{}),a=jn(pe(qn(),"tscloud-bun-layer-"));try{let c=i?`https://github.com/oven-sh/bun/releases/download/bun-v${i}/${r}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${r}.zip`;s(`downloading Bun ${i||"latest"} (${n})`);let u=pe(a,"bun.zip");Jn(c,u),s("extracting bun binary"),ot("unzip",["-o","-q",u,"-d",a],{stdio:"inherit"});let d=lt(pe(a,r,"bun"));s("packaging layer");let m=[{name:"bootstrap",data:Qn("bun"),mode:493},{name:"runtime.mjs",data:gd(),mode:420},{name:"bin/bun",data:d,mode:493}];return{zip:_t(m),architecture:n,version:i||"latest",fileCount:m.length}}finally{Kn(a,{recursive:!0,force:!0})}}function Jn(e,n){ot("curl",["-fsSL","-o",n,e],{stdio:["ignore","ignore","inherit"]})}function Os(e){let n=ot("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),i=JSON.parse(n).find((s)=>s.version.startsWith(`v${e}.`));if(!i)throw Error(`No Node release found for major version ${e}`);return i.version.replace(/^v/,"")}import{AsyncLocalStorage as Bs}from"node:async_hooks";import{createHash as $s}from"node:crypto";var rc="x-ts-cloud-invoke-depth",nc="x-ts-cloud-invoke-chain",ic="x-ts-cloud-trace-id";function fd(e){return $s("sha256").update(e).digest("hex").slice(0,8)}var Xi={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function qt(e,n){if(typeof e.get==="function")return e.get(n)??void 0;let r=e;return r[n]??r[n.toLowerCase()]??r[n.toUpperCase()]}function hd(e,n=64){if(!e)return[];return e.split(".").map((r)=>r.trim()).filter((r)=>/^[0-9a-f]{8}$/.test(r)).slice(-n)}function yd(e,n=Xi){let r=fd(e.functionId),i=hd(qt(e.headers,nc)),s=e.traceId??qt(e.headers,ic)??crypto.randomUUID(),a=[...i,r],c=i.filter((g)=>g===r).length,u=i[i.length-1]===r,d=Number.parseInt(qt(e.headers,rc)??"",10),m=Math.max(a.length,Number.isFinite(d)?d+1:0),p="ok";if(m>n.maxDepth)p="depth_exceeded";else if(c>=n.maxRepeats)p="cycle_detected";else if(u&&n.maxRepeats<=1)p="self_invocation";return{reason:p,depth:m,chain:a,traceId:s,selfInvocation:u,repeats:c,propagate:{[rc]:String(m),[nc]:a.join("."),[ic]:s}}}var Yn={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 ss{limits;clock;traces=new Map;breakers=new Map;constructor(e=Xi,n=()=>Date.now()){this.limits=e;this.clock=n}check(e){let n=this.clock();this.expireTraces(n);let r=yd(e,this.limits),i=this.breakers.get(e.functionId);if(i?.openUntil!=null&&i.openUntil>n)return this.deny(e.functionId,r,"breaker_open",n,!1);if(r.reason!=="ok")return this.deny(e.functionId,r,r.reason,n,!0);let s=this.traces.get(r.traceId)??{count:0,firstAt:n};if(s.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(r.traceId,s),this.deny(e.functionId,r,"trace_budget_exceeded",n,!0);if(this.traces.set(r.traceId,{count:s.count+1,firstAt:s.firstAt}),i)this.breakers.set(e.functionId,{consecutiveBlocks:0});return{...r,allowed:!0,reason:"ok",propagate:r.propagate}}deny(e,n,r,i,s){if(s){let a=this.breakers.get(e)??{consecutiveBlocks:0},c=a.consecutiveBlocks+1;this.breakers.set(e,{consecutiveBlocks:c,openUntil:c>=this.limits.breakerThreshold?i+this.limits.breakerCooldownMs:a.openUntil})}return{...n,allowed:!1,reason:r,message:Yn[r]}}breakerOpen(e){let n=this.breakers.get(e);return n?.openUntil!=null&&n.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[n,r]of this.traces)if(e-r.firstAt>this.limits.traceWindowMs)this.traces.delete(n)}get trackedTraces(){return this.traces.size}}function oc(e){return{...e.propagate}}function sc(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??Yn[e.reason],depth:e.depth,traceId:e.traceId}}}var bd=new Bs;function Zn(e){let n=globalThis.process?.env?.[e];if(n==null||n==="")return;return n!=="0"&&n.toLowerCase()!=="false"}function Fs(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function wp(e){let n=e===!1?{enabled:!1}:e??{},r=Zn("TS_CLOUD_RECURSION_PROTECTION"),i=Zn("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:r??n.enabled??!0,detectionOnly:i??n.detectionOnly??!1,limits:{...Xi,...n.limits},functionId:n.functionId??Fs()}}var ve,ae;function Ap(){let e=globalThis.fetch;if(!e||ve===e)return()=>{};ae=e;let n=async(r,i)=>{let s=bd.getStore();if(!s)return ae(r,i);let a=new Headers(i?.headers??(r instanceof Request?r.headers:void 0));for(let[c,u]of Object.entries(oc(s)))a.set(c,u);if(r instanceof Request)return ae(new Request(r,{headers:a}),i);return ae(r,{...i,headers:a})};return Object.assign(n,e),globalThis.fetch=n,ve=n,()=>{if(globalThis.fetch===ve&&ae)globalThis.fetch=ae;ve=void 0}}var ut,zt;function Rp(e){if(!ut||JSON.stringify(zt)!==JSON.stringify(e))ut=new ss(e),zt=e;return ut}function gh(){if(ut=void 0,zt=void 0,ve&&ae&&globalThis.fetch===ve)globalThis.fetch=ae;ve=void 0,ae=void 0}function Sd(e,n){let r=wp(n);if(!r.enabled)return;let i=Rp(r.limits),s={functionId:r.functionId,headers:e},a=i.check(s);return{verdict:a,blocked:!a.allowed&&!r.detectionOnly,observed:!a.allowed&&r.detectionOnly}}function vd(e,n){return Ap(),bd.run(e,n)}function fh(e){let n=e,r=n?.default??n;if(typeof r==="function")return{fetch:r};return{fetch:r?.fetch??n?.fetch,queue:r?.queue??n?.queue,cli:r?.cli??n?.cli}}var Gs=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function _s(e){if(!e)return!0;return Gs.test(e)}function Ws(e){if(e?.maintenance)return e.maintenance;let n=globalThis.process?.env??{};return{enabled:n.MAINTENANCE_MODE==="1"||n.MAINTENANCE_MODE==="true",bypassSecret:n.MAINTENANCE_BYPASS_SECRET}}function Ip(e){let n=e.requestContext?.domainName??"localhost",r=e.rawQueryString?`?${e.rawQueryString}`:"",i=`https://${n}${e.rawPath||"/"}${r}`,s=new Headers;for(let[u,d]of Object.entries(e.headers??{}))if(d!==void 0)s.set(u,d);if(e.cookies?.length)s.set("cookie",e.cookies.join("; "));let a=e.requestContext.http.method,c;if(e.body!==void 0&&a!=="GET"&&a!=="HEAD")c=e.isBase64Encoded?new Uint8Array(Buffer.from(e.body,"base64")):new TextEncoder().encode(e.body);return new Request(i,{method:a,headers:s,body:c})}async function Cd(e){let n={},r=[],i=typeof e.headers.getSetCookie==="function"?e.headers.getSetCookie():[];for(let c of i)r.push(c);e.headers.forEach((c,u)=>{if(u.toLowerCase()==="set-cookie")return;n[u]=c});let s=Buffer.from(await e.arrayBuffer()),a=_s(e.headers.get("content-type"));return{statusCode:e.status,headers:n,...r.length?{cookies:r}:{},body:a?s.toString("utf-8"):s.toString("base64"),isBase64Encoded:!a}}function Pp(e,n){return async(r)=>{if(r.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 i=Ws(n);if(i.enabled){let c=r.headers?.["x-maintenance-bypass"]??r.cookies?.find((u)=>u.startsWith("tscloud_bypass="))?.split("=")[1];if(!i.bypassSecret||c!==i.bypassSecret)return{statusCode:503,headers:{"content-type":"text/plain","retry-after":"120"},body:"Service temporarily unavailable (maintenance mode)",isBase64Encoded:!1}}let s=Sd(r.headers??{},n?.recursionProtection);if(s?.blocked){let c=sc(s.verdict);return{statusCode:c.status,headers:{...c.headers,"retry-after":"60"},body:JSON.stringify(c.body),isBase64Encoded:!1}}let a=Ip(r);if(!s){let c=await e(a);return Cd(c)}if(s.observed)console.warn(`[ts-cloud] recursion detected (${s.verdict.reason}) at depth ${s.verdict.depth}; detection-only mode let it run`);return vd(s.verdict,async()=>Cd(await e(a)))}}function Vs(e){try{return JSON.parse(e)}catch{return e}}function Dp(e){return async(n)=>{let r=[];if(n.warmer)return{batchItemFailures:r};if(!e)return{batchItemFailures:r};for(let i of n.Records??[])try{await e(Vs(i.body),i)}catch{r.push({itemIdentifier:i.messageId})}return{batchItemFailures:r}}}function kp(e){return async(n)=>{if(n.warmer)return{statusCode:0,output:"warm"};if(!e)return{statusCode:501,output:"No CLI handler configured"};return e(n)}}function hh(e,n){return{http:Pp(e.fetch,n),queue:Dp(e.queue),cli:kp(e.cli)}}function Td(e={}){let n=e.socketPath??"/tmp/.tscloud-fpm.sock",r=e.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
|
|
7310
|
+
`}import{execFileSync as ut}from"node:child_process";import{mkdtempSync as lr,readFileSync as mt,rmSync as ur}from"node:fs";import{tmpdir as dr}from"node:os";import{dirname as ga,join as ge}from"node:path";import{fileURLToPath as ya}from"node:url";function mr(){return ga(ya(import.meta.url))}function wd(){return mt(ge(mr(),"runtime.mjs"),"utf-8")}function pr(e){return mt(ge(mr(),`${e}-bootstrap`),"utf-8")}function Ah(e){let n=e.architecture??"x86_64",r=n==="arm64"?"arm64":"x64",i=e.version.replace(/^v/,""),s=e.onStep??(()=>{}),a=lr(ge(dr(),"tscloud-node-layer-"));try{let c=i.includes(".")?i:fa(i),u=`node-v${c}-linux-${r}`,d=`https://nodejs.org/dist/v${c}/${u}.tar.xz`;s(`downloading Node ${c} (${n})`);let m=ge(a,"node.tar.xz");gr(d,m),s("extracting node binary"),ut("tar",["-xf",m,"-C",a,`${u}/bin/node`],{stdio:"inherit"});let p=mt(ge(a,u,"bin","node"));s("packaging layer");let g=[{name:"bootstrap",data:pr("node"),mode:493},{name:"runtime.mjs",data:wd(),mode:420},{name:"bin/node",data:p,mode:493}];return{zip:$t(g),architecture:n,version:c,fileCount:g.length}}finally{ur(a,{recursive:!0,force:!0})}}function Rh(e){let n=e.architecture??"x86_64",r=n==="arm64"?"bun-linux-aarch64":"bun-linux-x64",i=e.version==="latest"?"":e.version.replace(/^v/,""),s=e.onStep??(()=>{}),a=lr(ge(dr(),"tscloud-bun-layer-"));try{let c=i?`https://github.com/oven-sh/bun/releases/download/bun-v${i}/${r}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${r}.zip`;s(`downloading Bun ${i||"latest"} (${n})`);let u=ge(a,"bun.zip");gr(c,u),s("extracting bun binary"),ut("unzip",["-o","-q",u,"-d",a],{stdio:"inherit"});let d=mt(ge(a,r,"bun"));s("packaging layer");let m=[{name:"bootstrap",data:pr("bun"),mode:493},{name:"runtime.mjs",data:wd(),mode:420},{name:"bin/bun",data:d,mode:493}];return{zip:$t(m),architecture:n,version:i||"latest",fileCount:m.length}}finally{ur(a,{recursive:!0,force:!0})}}function gr(e,n){ut("curl",["-fsSL","-o",n,e],{stdio:["ignore","ignore","inherit"]})}function fa(e){let n=ut("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),i=JSON.parse(n).find((s)=>s.version.startsWith(`v${e}.`));if(!i)throw Error(`No Node release found for major version ${e}`);return i.version.replace(/^v/,"")}import{AsyncLocalStorage as ba}from"node:async_hooks";import{createHash as ha}from"node:crypto";var dc="x-ts-cloud-invoke-depth",uc="x-ts-cloud-invoke-chain",pc="x-ts-cloud-trace-id";function Ad(e){return ha("sha256").update(e).digest("hex").slice(0,8)}var to={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function en(e,n){if(typeof e.get==="function")return e.get(n)??void 0;let r=e;return r[n]??r[n.toLowerCase()]??r[n.toUpperCase()]}function Rd(e,n=64){if(!e)return[];return e.split(".").map((r)=>r.trim()).filter((r)=>/^[0-9a-f]{8}$/.test(r)).slice(-n)}function Id(e,n=to){let r=Ad(e.functionId),i=Rd(en(e.headers,uc)),s=e.traceId??en(e.headers,pc)??crypto.randomUUID(),a=[...i,r],c=i.filter((g)=>g===r).length,u=i[i.length-1]===r,d=Number.parseInt(en(e.headers,dc)??"",10),m=Math.max(a.length,Number.isFinite(d)?d+1:0),p="ok";if(m>n.maxDepth)p="depth_exceeded";else if(c>=n.maxRepeats)p="cycle_detected";else if(u&&n.maxRepeats<=1)p="self_invocation";return{reason:p,depth:m,chain:a,traceId:s,selfInvocation:u,repeats:c,propagate:{[dc]:String(m),[uc]:a.join("."),[pc]:s}}}var yr={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 gs{limits;clock;traces=new Map;breakers=new Map;constructor(e=to,n=()=>Date.now()){this.limits=e;this.clock=n}check(e){let n=this.clock();this.expireTraces(n);let r=Id(e,this.limits),i=this.breakers.get(e.functionId);if(i?.openUntil!=null&&i.openUntil>n)return this.deny(e.functionId,r,"breaker_open",n,!1);if(r.reason!=="ok")return this.deny(e.functionId,r,r.reason,n,!0);let s=this.traces.get(r.traceId)??{count:0,firstAt:n};if(s.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(r.traceId,s),this.deny(e.functionId,r,"trace_budget_exceeded",n,!0);if(this.traces.set(r.traceId,{count:s.count+1,firstAt:s.firstAt}),i)this.breakers.set(e.functionId,{consecutiveBlocks:0});return{...r,allowed:!0,reason:"ok",propagate:r.propagate}}deny(e,n,r,i,s){if(s){let a=this.breakers.get(e)??{consecutiveBlocks:0},c=a.consecutiveBlocks+1;this.breakers.set(e,{consecutiveBlocks:c,openUntil:c>=this.limits.breakerThreshold?i+this.limits.breakerCooldownMs:a.openUntil})}return{...n,allowed:!1,reason:r,message:yr[r]}}breakerOpen(e){let n=this.breakers.get(e);return n?.openUntil!=null&&n.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[n,r]of this.traces)if(e-r.firstAt>this.limits.traceWindowMs)this.traces.delete(n)}get trackedTraces(){return this.traces.size}}function mc(e){return{...e.propagate}}function gc(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??yr[e.reason],depth:e.depth,traceId:e.traceId}}}var Pd=new ba;function fr(e){let n=globalThis.process?.env?.[e];if(n==null||n==="")return;return n!=="0"&&n.toLowerCase()!=="false"}function no(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function Lp(e){let n=e===!1?{enabled:!1}:e??{},r=fr("TS_CLOUD_RECURSION_PROTECTION"),i=fr("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:r??n.enabled??!0,detectionOnly:i??n.detectionOnly??!1,limits:{...to,...n.limits},functionId:n.functionId??no()}}var Ce,ce;function Mp(){let e=globalThis.fetch;if(!e||Ce===e)return()=>{};ce=e;let n=async(r,i)=>{let s=Pd.getStore();if(!s)return ce(r,i);let a=new Headers(i?.headers??(r instanceof Request?r.headers:void 0));for(let[c,u]of Object.entries(mc(s)))a.set(c,u);if(r instanceof Request)return ce(new Request(r,{headers:a}),i);return ce(r,{...i,headers:a})};return Object.assign(n,e),globalThis.fetch=n,Ce=n,()=>{if(globalThis.fetch===Ce&&ce)globalThis.fetch=ce;Ce=void 0}}var pt,tn;function Up(e){if(!pt||JSON.stringify(tn)!==JSON.stringify(e))pt=new gs(e),tn=e;return pt}function Ih(){if(pt=void 0,tn=void 0,Ce&&ce&&globalThis.fetch===Ce)globalThis.fetch=ce;Ce=void 0,ce=void 0}function Dd(e,n){let r=Lp(n);if(!r.enabled)return;let i=Up(r.limits),s={functionId:r.functionId,headers:e},a=i.check(s);return{verdict:a,blocked:!a.allowed&&!r.detectionOnly,observed:!a.allowed&&r.detectionOnly}}function kd(e,n){return Mp(),Pd.run(e,n)}function Ph(e){let n=e,r=n?.default??n;if(typeof r==="function")return{fetch:r};return{fetch:r?.fetch??n?.fetch,queue:r?.queue??n?.queue,cli:r?.cli??n?.cli}}var ro=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function io(e){if(!e)return!0;return ro.test(e)}function so(e){if(e?.maintenance)return e.maintenance;let n=globalThis.process?.env??{};return{enabled:n.MAINTENANCE_MODE==="1"||n.MAINTENANCE_MODE==="true",bypassSecret:n.MAINTENANCE_BYPASS_SECRET}}function Bp(e){let n=e.requestContext?.domainName??"localhost",r=e.rawQueryString?`?${e.rawQueryString}`:"",i=`https://${n}${e.rawPath||"/"}${r}`,s=new Headers;for(let[u,d]of Object.entries(e.headers??{}))if(d!==void 0)s.set(u,d);if(e.cookies?.length)s.set("cookie",e.cookies.join("; "));let a=e.requestContext.http.method,c;if(e.body!==void 0&&a!=="GET"&&a!=="HEAD")c=e.isBase64Encoded?new Uint8Array(Buffer.from(e.body,"base64")):new TextEncoder().encode(e.body);return new Request(i,{method:a,headers:s,body:c})}async function Nd(e){let n={},r=[],i=typeof e.headers.getSetCookie==="function"?e.headers.getSetCookie():[];for(let c of i)r.push(c);e.headers.forEach((c,u)=>{if(u.toLowerCase()==="set-cookie")return;n[u]=c});let s=Buffer.from(await e.arrayBuffer()),a=io(e.headers.get("content-type"));return{statusCode:e.status,headers:n,...r.length?{cookies:r}:{},body:a?s.toString("utf-8"):s.toString("base64"),isBase64Encoded:!a}}function Fp(e,n){return async(r)=>{if(r.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 i=so(n);if(i.enabled){let c=r.headers?.["x-maintenance-bypass"]??r.cookies?.find((u)=>u.startsWith("tscloud_bypass="))?.split("=")[1];if(!i.bypassSecret||c!==i.bypassSecret)return{statusCode:503,headers:{"content-type":"text/plain","retry-after":"120"},body:"Service temporarily unavailable (maintenance mode)",isBase64Encoded:!1}}let s=Dd(r.headers??{},n?.recursionProtection);if(s?.blocked){let c=gc(s.verdict);return{statusCode:c.status,headers:{...c.headers,"retry-after":"60"},body:JSON.stringify(c.body),isBase64Encoded:!1}}let a=Bp(r);if(!s){let c=await e(a);return Nd(c)}if(s.observed)console.warn(`[ts-cloud] recursion detected (${s.verdict.reason}) at depth ${s.verdict.depth}; detection-only mode let it run`);return kd(s.verdict,async()=>Nd(await e(a)))}}function ao(e){try{return JSON.parse(e)}catch{return e}}function jp(e){return async(n)=>{let r=[];if(n.warmer)return{batchItemFailures:r};if(!e)return{batchItemFailures:r};for(let i of n.Records??[])try{await e(ao(i.body),i)}catch{r.push({itemIdentifier:i.messageId})}return{batchItemFailures:r}}}function Vp(e){return async(n)=>{if(n.warmer)return{statusCode:0,output:"warm"};if(!e)return{statusCode:501,output:"No CLI handler configured"};return e(n)}}function Dh(e,n){return{http:Fp(e.fetch,n),queue:jp(e.queue),cli:Vp(e.cli)}}function xd(e={}){let n=e.socketPath??"/tmp/.tscloud-fpm.sock",r=e.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
|
|
7313
7311
|
[global]
|
|
7314
7312
|
daemonize = no
|
|
7315
7313
|
error_log = ${e.errorLog??"/tmp/storage/logs/php-fpm.log"}
|
|
@@ -7326,4 +7324,4 @@ decorate_workers_output = no
|
|
|
7326
7324
|
php_admin_value[error_log] = /dev/stderr
|
|
7327
7325
|
php_admin_flag[log_errors] = on
|
|
7328
7326
|
clear_env = no
|
|
7329
|
-
`}import{readFileSync as Us}from"node:fs";import{dirname as Hs,join as Xn}from"node:path";import{fileURLToPath as js}from"node:url";function Ks(){return Xn(Hs(js(import.meta.url)),"runtime-assets")}function Nn(){let e=Ks(),n=(r)=>Us(Xn(e,r),"utf-8");return[{path:"bootstrap",contents:n("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:n("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:n("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:n("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:n("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:Td(),mode:420}]}function ac(e={}){let n=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:n,CACHE_DRIVER:n,SESSION_DRIVER:n,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 Ed=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];import{execFileSync as dt}from"node:child_process";import{existsSync as qs,mkdirSync as zs,mkdtempSync as Qs,readdirSync as Js,readFileSync as Ys,rmSync as Zs,statSync as ir,writeFileSync as Xs}from"node:fs";import{tmpdir as ea}from"node:os";import{join as Me,relative as ta}from"node:path";function*sr(e){for(let n of Js(e)){let r=Me(e,n);if(ir(r).isDirectory())yield*sr(r);else yield r}}function yh(e={}){let n=e.architecture??"x86_64",r=e.platform??(n==="arm64"?"linux/arm64":"linux/amd64"),i=e.onStep??(()=>{}),s=Qs(Me(ea(),"tscloud-php-layer-")),a="tscloud-php-layer:build";try{Xs(Me(s,"Dockerfile"),md(e)),i("Building PHP runtime image (docker)"),dt("docker",["build","--platform",r,"-t","tscloud-php-layer:build",s],{stdio:"inherit"}),i("Extracting /opt/php from image");let c=dt("docker",["create","--platform",r,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),u=Me(s,"opt");zs(u,{recursive:!0});try{dt("docker",["cp",`${c}:/opt/php`,Me(u,"php")],{stdio:"inherit"})}finally{dt("docker",["rm",c],{stdio:"ignore"})}if(!qs(Me(u,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let d=[];for(let y of sr(u)){let f=ta(u,y).replace(/\\/g,"/"),h=ir(y).mode&73?493:420;d.push({name:f,data:Ys(y),mode:h})}i("Injecting runtime assets");let m=new Set(Nn().map((y)=>y.path)),p=d.filter((y)=>!m.has(y.name));for(let y of Nn())p.push({name:y.path,data:y.contents,mode:y.mode});return i("Packaging layer ZIP"),{zip:_t(p),architecture:n,fileCount:p.length}}finally{Zs(s,{recursive:!0,force:!0})}}import{execSync as na}from"node:child_process";import{createHash as ra}from"node:crypto";import{readdirSync as ia,readFileSync as sa,statSync as ar}from"node:fs";import{join as aa,relative as or,resolve as Jt}from"node:path";var Np=[".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 oa(e,n){return n.some((r)=>e===r||e.startsWith(`${r}/`))}function*cr(e,n,r){for(let i of ia(e)){let s=aa(e,i),a=or(n,s).replace(/\\/g,"/");if(oa(a,r))continue;if(ar(s).isDirectory())yield*cr(s,n,r);else yield s}}function as(e){if(e.skipBuild)return;let n=Jt(e.projectRoot??process.cwd()),r=e.app.build??Ed;for(let i of r)e.onStep?.(`build: ${i}`),na(i,{stdio:"inherit",cwd:n})}function cs(e,n=[]){let r=Jt(e),i=[...Np,wn(),...n],s=[];for(let a of cr(r,r,i)){let c=or(r,a).replace(/\\/g,"/"),u=(ar(a).mode&73)!==0;s.push({name:c,data:sa(a),mode:u?493:420})}return s}function cc(e){let n=Jt(e.projectRoot??process.cwd());as(e),e.onStep?.("packaging application tree");let r=cs(n,e.exclude);if(!r.length)throw Error(`No files to package under ${n}`);let i=_t(r),s=e.app.handlers?.http??"public/index.php";return{zip:i,sha256:ra("sha256").update(i).digest("hex"),handlers:{http:s,queue:e.app.handlers?.queue??s,cli:e.app.handlers?.cli??s},fileCount:r.length}}class wd{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let n=`asset-opt-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.optimizations.set(n,r),r}createImageOptimization(e){let n=`image-opt-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.imageConfigs.set(n,r),r}createSSGConfig(e){let n=`ssg-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.ssgConfigs.set(n,r),r}createPrerenderConfig(e){let n=`prerender-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.prerenderConfigs.set(n,r),r}listOptimizations(){return Array.from(this.optimizations.values())}listImageConfigs(){return Array.from(this.imageConfigs.values())}clear(){this.optimizations.clear(),this.imageConfigs.clear(),this.ssgConfigs.clear(),this.prerenderConfigs.clear()}}var bh=new wd;class lc{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,n){let r=`lifecycle-${Date.now()}-${this.counter++}`,i={id:r,transitions:e,expiration:n};return this.policies.set(r,i),i}enableVersioning(e=!1){let n=`versioning-${Date.now()}-${this.counter++}`,r={id:n,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(n,r),r}createReplicationRule(e,n,r){let i=`replication-${Date.now()}-${this.counter++}`,s={id:i,sourceRegion:e,destRegion:n,destBucket:r};return this.replicationRules.set(i,s),s}createIntelligentTiering(e,n){let r=`tiering-${Date.now()}-${this.counter++}`,i={id:r,archiveDays:e,deepArchiveDays:n};return this.tieringConfigs.set(r,i),i}enableObjectLock(e){let n=`object-lock-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(n,r),r}enableTransferAcceleration(e){let n=`transfer-accel-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(n,r),r}createAccessPoint(e){let n=`access-point-${Date.now()}-${this.counter++}`,r={id:n,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(n,r),r}createGlacierArchive(e){let n=`glacier-${Date.now()}-${this.counter++}`,r={id:n,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(n,r),r}createInventory(e){let n=`inventory-${Date.now()}-${this.counter++}`,r={id:n,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(n,r),r}createBatchOperation(e){let n=`batch-op-${Date.now()}-${this.counter++}`,r={id:n,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(n,r),r}executeBatchOperation(e){let n=this.batchOps.get(e);if(!n)throw Error(`Batch operation not found: ${e}`);return n.status="in_progress",n.totalObjects=1000,n.processedObjects=0,n}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,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(n,r),r}createSQSNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,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(n,r),r}createSNSNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,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(n,r),r}generateObjectLockCF(e){let n={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)n.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)n.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return n}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 n=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",r=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",i={Event:e.events[0],[r]:e.destination.arn};if(e.filter)i.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[n]:[i]}}}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 xp=new lc;class Ad{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,n=30,r=10){let i=`health-${Date.now()}-${this.counter++}`,s={id:i,url:e,interval:n,timeout:r,status:"healthy"};return this.checks.set(i,s),s}createSyntheticMonitor(e,n,r,i){let s=`synthetic-${Date.now()}-${this.counter++}`,a={id:s,name:e,script:n,frequency:r,locations:i};return this.synthetics.set(s,a),a}trackUptime(e,n,r){let i=`uptime-${Date.now()}-${this.counter++}`,s=n/(n+r)*100,a={id:i,resource:e,uptime:n,downtime:r,availability:s};return this.uptimeTrackers.set(i,a),a}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var Sh=new Ad;class Rd{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,n,r,i){let s=`waf-${Date.now()}-${this.counter++}`,a={id:s,name:e,priority:n,action:r,conditions:i};return this.wafRules.set(s,a),a}enableShield(e,n="standard"){let r=`shield-${Date.now()}-${this.counter++}`,i={id:r,resourceArn:e,protectionType:n};return this.shieldProtections.set(r,i),i}createSecurityGroup(e,n,r){let i=`sg-${Date.now()}-${this.counter++}`,s={id:i,name:e,vpcId:n,rules:r};return this.securityGroups.set(i,s),s}createNACL(e,n){let r=`nacl-${Date.now()}-${this.counter++}`,i={id:r,vpcId:e,rules:n};return this.nacls.set(r,i),i}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var vh=new Rd;class Id{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,n){let r=`tagging-${Date.now()}-${this.counter++}`,i={id:r,tags:e,resources:n};return this.strategies.set(r,i),i}createCostAllocation(e,n){let r=`cost-${Date.now()}-${this.counter++}`,i={id:r,tagKey:e,allocations:n};return this.allocations.set(r,i),i}createResourceGroup(e,n,r){let i=`group-${Date.now()}-${this.counter++}`,s={id:i,name:e,query:{resourceTypeFilters:n,tagFilters:r}};return this.groups.set(i,s),s}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var Ch=new Id;export{Em,wm,ua,ol,pa,ma,wn,ze,I,ga,sl,H,Fr,w,su,Y,jr,fa,Xo,de,U,Qo,au,cu,lu,du,l,o,Am,Rm,T,ha,ya,ba,Im,Pm,$e,Sa,Fi,uu,Dm,km,He,Dt,va,al,cl,Nm,ll,dl,ul,Yo,Ca,st,Zo,An,ji,Rn,Ge,pu,es,ts,Ta,Ea,wa,Aa,Ra,Ia,Ae,j,mu,gu,pl,b,M,at,N,ml,kt,ye,Qt,xm,gl,Re,rs,qe,Yt,Vi,Ie,ns,Le,fu,zi,Pe,De,oe,Hi,X,Zt,Nt,ke,t,In,_m,fl,Pa,Om,$m,Lm,Mm,Da,Um,Bm,Fm,jm,Vm,zm,Hm,Gm,qm,Wm,Km,Jm,hu,yu,bu,Su,vu,Cu,Tu,er,hl,yl,Vr,Gi,Xm,bl,Qm,Ym,Pn,Zm,eg,tg,rg,ng,ig,Eu,wu,Au,Ru,Iu,qi,og,Dn,Pu,Sl,Du,ka,be,ku,Nu,xt,is,tr,xu,vl,_u,Ou,$u,Cl,Se,sg,ag,cg,lg,Lu,dg,Ne,ug,pg,mg,Na,xa,Mu,Tl,El,gg,fg,hg,yg,bg,Uu,_a,Sg,vg,Cg,Tg,Eg,Bu,Fu,wg,Ag,Rg,Ig,Pg,Dg,kg,ju,Ng,wl,Oa,xg,_g,Og,$g,Al,Rl,Il,Lg,$a,Vu,zu,Hu,Gu,La,qu,Mg,Ug,Bg,Fg,jg,Vg,zg,Wu,Ku,Ju,Xu,Pl,Hg,Gg,qg,Wg,Kg,Jg,Xg,Qg,Yg,Qu,Yu,Zu,ep,Zg,ef,Dl,tf,kl,Nl,xl,_l,rf,nf,of,sf,ct,Wi,af,cf,lf,df,uf,pf,mf,gf,tp,ff,hf,Ol,$l,yf,bf,rp,Sf,vf,Cf,Tf,Ef,wf,Af,Rf,If,Pf,Df,kf,Nf,xf,_f,Of,$f,Lf,Mf,Uf,Bf,Ma,np,Ua,ip,Ba,op,Fa,sp,ja,ap,zr,cp,Va,lp,Ki,dp,za,up,Ha,pp,Ll,Ff,Ml,jf,Ga,mp,Hr,gp,Ul,Vf,qa,fp,Bl,zf,Fl,Hf,jl,Gf,Wa,hp,Vl,qf,zl,Wf,Hl,Kf,Gl,Jf,Ka,yp,Ja,bp,ql,Xf,Wl,Qf,Kl,Yf,Jl,Zf,Xl,eh,Ql,th,Xa,Sp,Yl,rh,Zl,nh,ed,ih,td,oh,rd,sh,nd,ah,id,od,sd,ad,cd,ch,ld,lh,dd,dh,ud,uh,_t,pd,vp,os,Qa,kn,Cp,Ji,rr,Ya,Za,Tp,Ep,ec,md,tc,gd,ph,mh,rc,nc,ic,fd,Xi,hd,yd,ss,oc,sc,bd,wp,Ap,Rp,gh,Sd,vd,fh,Ip,Cd,Pp,Dp,kp,hh,Td,Nn,ac,Ed,yh,Np,as,cs,cc,wd,bh,lc,xp,Ad,Sh,Rd,vh,Id,Ch};
|
|
7327
|
+
`}import{readFileSync as oo}from"node:fs";import{dirname as co,join as hr}from"node:path";import{fileURLToPath as lo}from"node:url";function uo(){return hr(co(lo(import.meta.url)),"runtime-assets")}function _n(){let e=uo(),n=(r)=>oo(hr(e,r),"utf-8");return[{path:"bootstrap",contents:n("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:n("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:n("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:n("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:n("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:xd(),mode:420}]}function fc(e={}){let n=e.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:n,CACHE_DRIVER:n,SESSION_DRIVER:n,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 _d=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];import{execFileSync as gt}from"node:child_process";import{existsSync as mo,mkdirSync as po,mkdtempSync as go,readdirSync as yo,readFileSync as fo,rmSync as ho,statSync as br,writeFileSync as bo}from"node:fs";import{tmpdir as So}from"node:os";import{join as $e,relative as Ao}from"node:path";function*Sr(e){for(let n of yo(e)){let r=$e(e,n);if(br(r).isDirectory())yield*Sr(r);else yield r}}function kh(e={}){let n=e.architecture??"x86_64",r=e.platform??(n==="arm64"?"linux/arm64":"linux/amd64"),i=e.onStep??(()=>{}),s=go($e(So(),"tscloud-php-layer-")),a="tscloud-php-layer:build";try{bo($e(s,"Dockerfile"),Ed(e)),i("Building PHP runtime image (docker)"),gt("docker",["build","--platform",r,"-t","tscloud-php-layer:build",s],{stdio:"inherit"}),i("Extracting /opt/php from image");let c=gt("docker",["create","--platform",r,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),u=$e(s,"opt");po(u,{recursive:!0});try{gt("docker",["cp",`${c}:/opt/php`,$e(u,"php")],{stdio:"inherit"})}finally{gt("docker",["rm",c],{stdio:"ignore"})}if(!mo($e(u,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let d=[];for(let y of Sr(u)){let f=Ao(u,y).replace(/\\/g,"/"),h=br(y).mode&73?493:420;d.push({name:f,data:fo(y),mode:h})}i("Injecting runtime assets");let m=new Set(_n().map((y)=>y.path)),p=d.filter((y)=>!m.has(y.name));for(let y of _n())p.push({name:y.path,data:y.contents,mode:y.mode});return i("Packaging layer ZIP"),{zip:$t(p),architecture:n,fileCount:p.length}}finally{ho(s,{recursive:!0,force:!0})}}import{execSync as Co}from"node:child_process";import{createHash as vo}from"node:crypto";import{readdirSync as To,readFileSync as Ro,statSync as Ar}from"node:fs";import{join as Po,relative as Cr,resolve as nn}from"node:path";var zp=[".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 Eo(e,n){return n.some((r)=>e===r||e.startsWith(`${r}/`))}function*vr(e,n,r){for(let i of To(e)){let s=Po(e,i),a=Cr(n,s).replace(/\\/g,"/");if(Eo(a,r))continue;if(Ar(s).isDirectory())yield*vr(s,n,r);else yield s}}function fs(e){if(e.skipBuild)return;let n=nn(e.projectRoot??process.cwd()),r=e.app.build??_d;for(let i of r)e.onStep?.(`build: ${i}`),Co(i,{stdio:"inherit",cwd:n})}function hs(e,n=[]){let r=nn(e),i=[...zp,An(),...n],s=[];for(let a of vr(r,r,i)){let c=Cr(r,a).replace(/\\/g,"/"),u=(Ar(a).mode&73)!==0;s.push({name:c,data:Ro(a),mode:u?493:420})}return s}function hc(e){let n=nn(e.projectRoot??process.cwd());fs(e),e.onStep?.("packaging application tree");let r=hs(n,e.exclude);if(!r.length)throw Error(`No files to package under ${n}`);let i=$t(r),s=e.app.handlers?.http??"public/index.php";return{zip:i,sha256:vo("sha256").update(i).digest("hex"),handlers:{http:s,queue:e.app.handlers?.queue??s,cli:e.app.handlers?.cli??s},fileCount:r.length}}class Od{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(e){let n=`asset-opt-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.optimizations.set(n,r),r}createImageOptimization(e){let n=`image-opt-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.imageConfigs.set(n,r),r}createSSGConfig(e){let n=`ssg-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.ssgConfigs.set(n,r),r}createPrerenderConfig(e){let n=`prerender-${Date.now()}-${this.counter++}`,r={id:n,...e};return this.prerenderConfigs.set(n,r),r}listOptimizations(){return Array.from(this.optimizations.values())}listImageConfigs(){return Array.from(this.imageConfigs.values())}clear(){this.optimizations.clear(),this.imageConfigs.clear(),this.ssgConfigs.clear(),this.prerenderConfigs.clear()}}var Nh=new Od;class yc{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,n){let r=`lifecycle-${Date.now()}-${this.counter++}`,i={id:r,transitions:e,expiration:n};return this.policies.set(r,i),i}enableVersioning(e=!1){let n=`versioning-${Date.now()}-${this.counter++}`,r={id:n,enabled:!0,mfaDelete:e};return this.versioningConfigs.set(n,r),r}createReplicationRule(e,n,r){let i=`replication-${Date.now()}-${this.counter++}`,s={id:i,sourceRegion:e,destRegion:n,destBucket:r};return this.replicationRules.set(i,s),s}createIntelligentTiering(e,n){let r=`tiering-${Date.now()}-${this.counter++}`,i={id:r,archiveDays:e,deepArchiveDays:n};return this.tieringConfigs.set(r,i),i}enableObjectLock(e){let n=`object-lock-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e.bucketName,mode:e.mode||"COMPLIANCE",retentionDays:e.retentionDays,retentionYears:e.retentionYears,legalHoldEnabled:e.legalHoldEnabled||!1};return this.objectLocks.set(n,r),r}enableTransferAcceleration(e){let n=`transfer-accel-${Date.now()}-${this.counter++}`,r={id:n,bucketName:e,enabled:!0,endpoint:`${e}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(n,r),r}createAccessPoint(e){let n=`access-point-${Date.now()}-${this.counter++}`,r={id:n,name:e.name,bucketName:e.bucketName,vpcId:e.vpcId,publicAccessBlock:e.publicAccessBlock!==!1,policy:e.policy};return this.accessPoints.set(n,r),r}createGlacierArchive(e){let n=`glacier-${Date.now()}-${this.counter++}`,r={id:n,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(n,r),r}createInventory(e){let n=`inventory-${Date.now()}-${this.counter++}`,r={id:n,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(n,r),r}createBatchOperation(e){let n=`batch-op-${Date.now()}-${this.counter++}`,r={id:n,operation:e.operation,manifestBucket:e.manifestBucket,manifestKey:e.manifestKey,priority:e.priority||10,status:"pending"};return this.batchOps.set(n,r),r}executeBatchOperation(e){let n=this.batchOps.get(e);if(!n)throw Error(`Batch operation not found: ${e}`);return n.status="in_progress",n.totalObjects=1000,n.processedObjects=0,n}getBatchOperationStatus(e){return this.batchOps.get(e)}createLambdaNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,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(n,r),r}createSQSNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,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(n,r),r}createSNSNotification(e){let n=`event-${Date.now()}-${this.counter++}`,r={id:n,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(n,r),r}generateObjectLockCF(e){let n={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:e.mode}}}};if(e.retentionDays)n.ObjectLockConfiguration.Rule.DefaultRetention.Days=e.retentionDays;if(e.retentionYears)n.ObjectLockConfiguration.Rule.DefaultRetention.Years=e.retentionYears;return n}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 n=e.destination.type==="Lambda"?"LambdaConfigurations":e.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",r=e.destination.type==="Lambda"?"Function":e.destination.type==="SQS"?"Queue":"Topic",i={Event:e.events[0],[r]:e.destination.arn};if(e.filter)i.Filter={S3Key:{Rules:[...e.filter.prefix?[{Name:"prefix",Value:e.filter.prefix}]:[],...e.filter.suffix?[{Name:"suffix",Value:e.filter.suffix}]:[]]}};return{NotificationConfiguration:{[n]:[i]}}}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 Hp=new yc;class $d{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,n=30,r=10){let i=`health-${Date.now()}-${this.counter++}`,s={id:i,url:e,interval:n,timeout:r,status:"healthy"};return this.checks.set(i,s),s}createSyntheticMonitor(e,n,r,i){let s=`synthetic-${Date.now()}-${this.counter++}`,a={id:s,name:e,script:n,frequency:r,locations:i};return this.synthetics.set(s,a),a}trackUptime(e,n,r){let i=`uptime-${Date.now()}-${this.counter++}`,s=n/(n+r)*100,a={id:i,resource:e,uptime:n,downtime:r,availability:s};return this.uptimeTrackers.set(i,a),a}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var xh=new $d;class Ld{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,n,r,i){let s=`waf-${Date.now()}-${this.counter++}`,a={id:s,name:e,priority:n,action:r,conditions:i};return this.wafRules.set(s,a),a}enableShield(e,n="standard"){let r=`shield-${Date.now()}-${this.counter++}`,i={id:r,resourceArn:e,protectionType:n};return this.shieldProtections.set(r,i),i}createSecurityGroup(e,n,r){let i=`sg-${Date.now()}-${this.counter++}`,s={id:i,name:e,vpcId:n,rules:r};return this.securityGroups.set(i,s),s}createNACL(e,n){let r=`nacl-${Date.now()}-${this.counter++}`,i={id:r,vpcId:e,rules:n};return this.nacls.set(r,i),i}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var _h=new Ld;class Md{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(e,n){let r=`tagging-${Date.now()}-${this.counter++}`,i={id:r,tags:e,resources:n};return this.strategies.set(r,i),i}createCostAllocation(e,n){let r=`cost-${Date.now()}-${this.counter++}`,i={id:r,tagKey:e,allocations:n};return this.allocations.set(r,i),i}createResourceGroup(e,n,r){let i=`group-${Date.now()}-${this.counter++}`,s={id:i,name:e,query:{resourceTypeFilters:n,tagFilters:r}};return this.groups.set(i,s),s}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var Oh=new Md;export{jr,ml,$m,Lm,Sa,gl,va,Ca,An,He,I,Ta,fl,H,Vr,w,hu,Y,zr,Ea,ts,ue,U,rs,yu,bu,Su,vu,l,o,Mm,Um,T,wa,Aa,Ra,Bm,Fm,Le,Ia,Vi,Cu,jm,Vm,Ge,Nt,Pa,hl,yl,zm,bl,Sl,vl,ns,Da,ct,is,Rn,zi,In,qe,Tu,os,ss,ka,Na,xa,_a,Oa,$a,Re,j,Eu,wu,Cl,b,M,lt,N,Tl,xt,be,Zt,Hm,El,Ie,as,We,er,Hi,Pe,cs,Me,Au,Gi,De,ke,se,qi,X,tr,_t,Ne,t,Pn,Gm,wl,La,qm,Wm,Km,Jm,Ma,Xm,Qm,Ym,Zm,eg,tg,rg,ng,ig,og,sg,ag,Ru,Iu,Pu,Du,ku,Nu,xu,rr,Al,Rl,Hr,Wi,cg,Il,lg,dg,Dn,ug,pg,mg,gg,fg,hg,Pl,Z,Ke,Ki,ls,kn,Ji,ds,_u,yg,Xi,us,Ou,$u,Lu,Mu,Uu,Bu,Qi,bg,Nn,Fu,Dl,ju,Ua,Se,Vu,zu,Ot,ps,nr,Hu,kl,Gu,qu,Wu,Nl,ve,Sg,vg,Cg,Tg,Ku,Eg,xe,wg,Ag,Rg,Ba,Fa,Ju,xl,_l,Ig,Pg,Dg,kg,Ng,Xu,ja,xg,_g,Og,$g,Lg,Qu,Yu,Mg,Ug,Bg,Fg,jg,Vg,zg,Zu,Hg,Ol,Va,Gg,qg,Wg,Kg,$l,Ll,Ml,Jg,za,ep,tp,rp,np,Ha,ip,Xg,Qg,Yg,Zg,ef,tf,rf,op,sp,ap,cp,Ul,nf,of,sf,af,cf,lf,df,uf,pf,lp,dp,up,pp,mf,gf,Bl,ff,Fl,jl,Vl,zl,hf,yf,bf,Sf,dt,Yi,vf,Cf,Tf,Ef,wf,Af,Rf,If,mp,Pf,Df,Hl,Gl,kf,Nf,gp,xf,_f,Of,$f,Lf,Mf,Uf,Bf,Ff,jf,Vf,zf,Hf,Gf,qf,Wf,Kf,Jf,Xf,Qf,Yf,Ga,fp,qa,hp,Wa,yp,Ka,bp,Ja,Sp,Gr,vp,Xa,Cp,Zi,Tp,Qa,Ep,Ya,wp,ql,Zf,Wl,eh,Za,Ap,qr,Rp,Kl,th,ec,Ip,Jl,rh,Xl,nh,Ql,ih,tc,Pp,Yl,oh,Zl,sh,ed,ah,td,ch,rc,Dp,nc,kp,rd,lh,nd,dh,id,uh,od,ph,sd,mh,ad,gh,ic,Np,cd,fh,ld,hh,dd,yh,ud,bh,pd,Sh,md,vh,gd,fd,hd,yd,bd,Ch,Sd,Th,vd,Eh,Cd,wh,$t,Td,xp,ms,oc,xn,_p,eo,ir,sc,ac,Op,$p,cc,Ed,lc,wd,Ah,Rh,dc,uc,pc,Ad,to,Rd,Id,gs,mc,gc,Pd,Lp,Mp,Up,Ih,Dd,kd,Ph,Bp,Nd,Fp,jp,Vp,Dh,xd,_n,fc,_d,kh,zp,fs,hs,hc,Od,Nh,yc,Hp,$d,xh,Ld,_h,Md,Oh};
|