@stacksjs/ts-cloud 0.16.51 → 0.16.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aws/index.js +1 -1
- package/dist/bin/{chunk-z06jkvvr.js → chunk-0xfy78nc.js} +4 -4
- package/dist/bin/chunk-1cccv502.js +1 -0
- package/dist/bin/{chunk-n5kdne4p.js → chunk-1q6wqzh1.js} +3 -3
- package/dist/bin/{chunk-ddyd6f14.js → chunk-28124w0n.js} +2 -2
- package/dist/bin/{chunk-ppd463ev.js → chunk-3mhzd931.js} +1 -1
- package/dist/bin/{chunk-q2rqmc2x.js → chunk-4crz28b9.js} +1 -1
- package/dist/bin/chunk-5s91mpty.js +1 -0
- package/dist/bin/chunk-6sfn8fjv.js +1 -0
- package/dist/bin/chunk-6tdt3ea9.js +1 -0
- package/dist/bin/{chunk-dv2he3vc.js → chunk-7cactd6c.js} +2 -2
- package/dist/bin/{chunk-2wh45zhk.js → chunk-7p70c4br.js} +2 -2
- package/dist/bin/{chunk-93yw46n7.js → chunk-8fh0gv4q.js} +1 -1
- package/dist/bin/chunk-8nfrknq3.js +1 -0
- package/dist/bin/{chunk-0wtshht7.js → chunk-95djv2ja.js} +1 -1
- package/dist/bin/{chunk-te52z1wk.js → chunk-9t78j764.js} +1 -1
- package/dist/bin/chunk-a4z8b18n.js +1 -0
- package/dist/bin/chunk-apqyj6gr.js +1 -0
- package/dist/bin/chunk-bn2sn094.js +1 -0
- package/dist/bin/chunk-bzbah8jm.js +1 -0
- package/dist/bin/chunk-bzpeqh5z.js +1 -0
- package/dist/bin/{chunk-mcg4wg4j.js → chunk-bzzwbkrx.js} +4 -4
- package/dist/bin/{chunk-f78wmcvb.js → chunk-cdseg15k.js} +2 -2
- package/dist/bin/{chunk-wv8060cw.js → chunk-dg8ceycc.js} +5 -5
- package/dist/bin/chunk-e0d34gcp.js +1 -0
- package/dist/bin/chunk-e3zsrpbj.js +1 -0
- package/dist/bin/{chunk-t970yjvz.js → chunk-ek27709c.js} +5 -5
- package/dist/bin/chunk-erdz4875.js +1 -0
- package/dist/bin/chunk-et6hzqpx.js +1 -0
- package/dist/bin/chunk-gee6a9zv.js +740 -0
- package/dist/bin/{chunk-ngmewar1.js → chunk-hkx5j0bn.js} +3 -3
- package/dist/bin/chunk-hrg9ygbz.js +1 -0
- package/dist/bin/{chunk-fjbhvhqb.js → chunk-hzc049ns.js} +1 -1
- package/dist/bin/{chunk-rwbdtxte.js → chunk-jvbe549p.js} +1 -1
- package/dist/bin/{chunk-5c4xh61a.js → chunk-jxm62h8r.js} +16 -16
- package/dist/bin/{chunk-a7hhzbvm.js → chunk-jyvr7eh5.js} +3 -3
- package/dist/bin/{chunk-cjagqdk3.js → chunk-k1kk78qg.js} +5 -5
- package/dist/bin/chunk-kj1e4xvg.js +1 -0
- package/dist/bin/{chunk-811k54jq.js → chunk-kqd186ky.js} +2 -2
- package/dist/bin/{chunk-we2raqk3.js → chunk-mdcv2vw1.js} +2 -2
- package/dist/bin/chunk-mpawwybt.js +1 -0
- package/dist/bin/{chunk-da6dmacg.js → chunk-n2jh5p5x.js} +2 -2
- package/dist/bin/chunk-n6hngvvb.js +1 -0
- package/dist/bin/chunk-n9aeark7.js +1 -0
- package/dist/bin/{chunk-7czb1kgg.js → chunk-nva480hg.js} +2 -2
- package/dist/bin/{chunk-yfa84s0c.js → chunk-p23wfy3r.js} +1 -1
- package/dist/bin/{chunk-ytzcsskk.js → chunk-p6qa21fr.js} +2 -2
- package/dist/bin/chunk-pexjxc5g.js +1 -0
- package/dist/bin/{chunk-sa9c8vb5.js → chunk-pr5c0q0k.js} +5 -5
- package/dist/bin/{chunk-m3xap663.js → chunk-q0takzyx.js} +4 -4
- package/dist/bin/{chunk-hhmqsrfc.js → chunk-rbyrd9we.js} +1 -1
- package/dist/bin/{chunk-gc199s7a.js → chunk-rmxexkvr.js} +60 -60
- package/dist/bin/{chunk-45thdtvf.js → chunk-rqvrjp8g.js} +36 -36
- package/dist/bin/chunk-s98wngxx.js +1 -0
- package/dist/bin/{chunk-83brtkvn.js → chunk-sbate1ky.js} +1 -1
- package/dist/bin/{chunk-5ny7rggt.js → chunk-sy4zws71.js} +1 -1
- package/dist/bin/chunk-t2ec6d8h.js +1 -0
- package/dist/bin/{chunk-fhe0mdjg.js → chunk-tbp1gf1p.js} +1 -1
- package/dist/bin/{chunk-734n0gkw.js → chunk-v0g82agx.js} +1 -1
- package/dist/bin/{chunk-f0vedy45.js → chunk-v9js2b1d.js} +1 -1
- package/dist/bin/{chunk-33ntxz01.js → chunk-z6xnegpe.js} +3 -3
- package/dist/bin/cli.js +239 -239
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/{chunk-qcv4twc6.js → chunk-184bvh5s.js} +19 -19
- package/dist/chunk-27ny16g8.js +1 -0
- package/dist/{chunk-pz33w7gv.js → chunk-2hma3g5q.js} +2 -2
- package/dist/chunk-2n3c5axm.js +1 -0
- package/dist/{chunk-6gnmrtp9.js → chunk-430acqjk.js} +19 -19
- package/dist/chunk-5yrabpmr.js +1 -0
- package/dist/{chunk-9ggg2ktx.js → chunk-7ag4wc74.js} +2 -2
- package/dist/{chunk-thdfk76k.js → chunk-80bgb48v.js} +2 -2
- package/dist/{chunk-8b2mxhcm.js → chunk-94z7s8ky.js} +5 -5
- package/dist/{chunk-53kyxata.js → chunk-9fvtnx6h.js} +90 -90
- package/dist/{chunk-6m8p1n88.js → chunk-a99wz633.js} +12 -12
- package/dist/{chunk-x4qye2rc.js → chunk-apj1eqcy.js} +4 -4
- package/dist/chunk-bg89ad2e.js +1 -0
- package/dist/{chunk-erfh93dq.js → chunk-c482jhc6.js} +2 -2
- package/dist/{chunk-zf5wdx6v.js → chunk-d245va6b.js} +1 -1
- package/dist/{chunk-ca191b00.js → chunk-e42gpavb.js} +5 -5
- package/dist/chunk-e5xg3p1x.js +1 -0
- package/dist/{chunk-ffyx50xx.js → chunk-gmtds745.js} +1 -1
- package/dist/chunk-hwm83kj0.js +464 -0
- package/dist/{chunk-p101nhg2.js → chunk-hybz2q8w.js} +4 -4
- package/dist/{chunk-j99nkav5.js → chunk-jyvnfny6.js} +3 -3
- package/dist/{chunk-4abbccq7.js → chunk-mp2y4t6w.js} +1 -1
- package/dist/{chunk-jytama4e.js → chunk-nhsefr22.js} +5 -5
- package/dist/{chunk-3ncnrrvm.js → chunk-qjp3f5y8.js} +7 -7
- package/dist/{chunk-0qgfe5ff.js → chunk-qyr5hn6v.js} +3 -3
- package/dist/{chunk-m9r0a1v9.js → chunk-smt4t6rc.js} +2 -2
- package/dist/{chunk-0cz2s19h.js → chunk-stc3ykm3.js} +2 -2
- package/dist/{chunk-4yqd62rd.js → chunk-v4vz0e85.js} +1 -1
- package/dist/{chunk-qcj3hkba.js → chunk-vgtqd3sb.js} +1 -1
- package/dist/{chunk-r5mk071y.js → chunk-wbbbpt4v.js} +5 -5
- package/dist/chunk-xfced13z.js +1 -0
- package/dist/{chunk-jtvw9d4x.js → chunk-y7k5872m.js} +1 -1
- package/dist/{chunk-xgc6hskd.js → chunk-yt8qgn5d.js} +6 -6
- package/dist/{chunk-prtvb2fh.js → chunk-zvcd6x45.js} +83 -83
- package/dist/deploy/index.js +1 -1
- package/dist/dns/index.js +1 -1
- package/dist/drivers/hetzner/client.d.ts +30 -0
- package/dist/drivers/hetzner/driver.d.ts +3 -2
- package/dist/drivers/hetzner/volumes.d.ts +9 -0
- package/dist/drivers/index.d.ts +4 -0
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/shared/compute-storage-agent.d.ts +3 -0
- package/dist/drivers/shared/compute-storage.d.ts +21 -0
- package/dist/drivers/shared/notifications.d.ts +3 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +19 -19
- 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 +1 -1
- package/dist/ui/data/backups.html +6 -6
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +5 -5
- package/dist/ui/integrations.html +1 -1
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +5 -5
- package/dist/ui/operations/jobs.html +6 -6
- package/dist/ui/operations/maintenance.html +6 -6
- package/dist/ui/operations/observability.html +6 -6
- package/dist/ui/operations/previews.html +6 -6
- package/dist/ui/operations/queue.html +6 -6
- package/dist/ui/operations/regions.html +5 -5
- package/dist/ui/operations/releases.html +6 -6
- package/dist/ui/operations/spend.html +5 -5
- package/dist/ui/operations/workloads.html +6 -6
- package/dist/ui/security.html +2 -2
- package/dist/ui/server/actions.html +6 -6
- package/dist/ui/server/activity.html +2 -2
- package/dist/ui/server/capacity.html +5 -5
- 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 +7 -7
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +1 -1
- package/dist/ui/server/sites.html +5 -5
- package/dist/ui/server/ssh-keys.html +6 -6
- package/dist/ui/server/team.html +6 -6
- package/dist/ui/server/terminal.html +2 -2
- package/dist/ui/serverless/alarms.html +6 -6
- package/dist/ui/serverless/assets.html +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 +1 -1
- package/dist/ui/serverless/functions.html +5 -5
- 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 +6 -6
- package/dist/ui-src/pages/server/metrics.stx +9 -0
- package/package.json +3 -3
- package/dist/bin/chunk-20dp8658.js +0 -1
- package/dist/bin/chunk-334jngt2.js +0 -1
- package/dist/bin/chunk-3k7y1h18.js +0 -1
- package/dist/bin/chunk-626npmtj.js +0 -1
- package/dist/bin/chunk-67vf8myy.js +0 -1
- package/dist/bin/chunk-74wppexz.js +0 -1
- package/dist/bin/chunk-87g6jcfm.js +0 -1
- package/dist/bin/chunk-8ya34jz7.js +0 -1
- package/dist/bin/chunk-964xmgb6.js +0 -1
- package/dist/bin/chunk-9qdrv6zp.js +0 -1
- package/dist/bin/chunk-azarn24c.js +0 -1
- package/dist/bin/chunk-d24ztt54.js +0 -724
- package/dist/bin/chunk-dpk5r544.js +0 -1
- package/dist/bin/chunk-f578z20t.js +0 -1
- package/dist/bin/chunk-f9469h6q.js +0 -1
- package/dist/bin/chunk-g6ph425d.js +0 -1
- package/dist/bin/chunk-m5jvp6ph.js +0 -1
- package/dist/bin/chunk-m7pbssep.js +0 -1
- package/dist/bin/chunk-n7xadeqe.js +0 -1
- package/dist/bin/chunk-p6wxv8yq.js +0 -1
- package/dist/bin/chunk-vpt43nwa.js +0 -1
- package/dist/bin/chunk-wgh66c5r.js +0 -1
- package/dist/bin/chunk-zywk12mp.js +0 -1
- package/dist/chunk-09d6pdgx.js +0 -1
- package/dist/chunk-21mmcmm7.js +0 -1
- package/dist/chunk-2gqm2h84.js +0 -1
- package/dist/chunk-dw0cvqdr.js +0 -448
- package/dist/chunk-jgsey18z.js +0 -1
- package/dist/chunk-qbsrs1gp.js +0 -1
- package/dist/chunk-tnqj2en4.js +0 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{Y,ts,kt,Pn}from"./chunk-33ntxz01.js";import{Yt,Vr}from"./chunk-2wh45zhk.js";var al={};Yt(al,{default:()=>Dr,handler:()=>yt});var cl={};Yt(cl,{default:()=>Nr,handler:()=>ft});var Yl={};Yt(Yl,{EmailAnalyticsModule:()=>Je,EmailRules:()=>_t,EmailScheduling:()=>Bt,EmailSearch:()=>Ot,EmailTemplates:()=>Ce,EmailThreading:()=>$t,SharedMailboxes:()=>Ft});var Zl={};Yt(Zl,{default:()=>ra,handler:()=>na});var ed={};Yt(ed,{CallAnalytics:()=>Ut,CallRecording:()=>Vt,Callbacks:()=>st,IVRBuilder:()=>we});var td={};Yt(td,{AbTesting:()=>me,LinkTracking:()=>Zt,MmsSupport:()=>qt,SmsAnalytics:()=>jt,SmsCampaigns:()=>Ht,SmsChatbot:()=>zt});var hm={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}},ym={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 sa=".ts-cloud",Zc="TS_CLOUD_STATE_DIR",gt=null;function aa(e){gt=e?.trim()||null}function ca(){return Boolean(process.env[Zc]?.trim()||gt)}function vn(){return process.env[Zc]?.trim()||gt||sa}function je(...e){return Ye(vn(),...e)}function A(e,...n){let r=vn();return pt(r)?Ye(r,...n):Ye(e,r,...n)}function la(e,n=process.cwd()){let r=(a,s)=>{let c=ur(a,s);return c===""||!c.startsWith("..")&&!pt(c)},i=pt(e)?e:Ye(n,e);return r(A(n),i)}function el(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}=el(e);return n?"serverless":"server"}function Mr(e){let{server:n,serverless:r}=el(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 eu(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??{}),a=e.sites?.main?.domain??i.find((s)=>s.domain)?.domain;if(a)return a;return`${e.project?.slug??"app"}.local`}function pr(e){let n=e.indexOf(".");return n>0?e.slice(n+1):void 0}function ne(e,n={}){let r=e.infrastructure?.compute?.managedServices?.mail,i=dr(r),a=n.environmentType??(n.environment?e.environments?.[n.environment]?.type:void 0),s=i.mode??(a==="production"?"server":"catcher"),c=s==="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.certPath&&g.keyPath),h=(i.accounts??[]).map((Q)=>({address:Q.address,password:Q.password,passwordPolicy:Q.passwordPolicy??"initial"})),S=typeof i.dkim==="object"&&i.dkim!==null?i.dkim:{},C=i.dkim===!1?!1:i.dkim===!0||c,P=typeof i.webmail==="object"&&i.webmail!==null?i.webmail:{},E=i.webmail===!1?!1:P.enabled??!0,v=d.includes(".")&&!d.endsWith(".local")&&!/^\d+\.\d+\.\d+\.\d+$/.test(d),I=P.domain===!1?void 0:P.domain??(c&&v?d:void 0),D=P.tls??(I?!1:y),N=[...new Set(P.aliases??[])].filter((Q)=>Q!==I),M=i.spam??{},F=i.delivery??(c?"direct":"none"),O=i.expose??c,G=pr(d),U=[...new Set([d,...G?[G]:[],...i.domains??[]])],ce=P.attachments?.maxFileBytes??20971520,q=P.attachments?.maxTotalBytes??20971520,J=P.attachments?.maxCount??20,K=P.undoSendSeconds??10;for(let[Q,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 ${Q} must be an integer from 0 to ${Te}`);return{enabled:eu(r),mode:s,version:i.version,hostname:d,domains:U,ports:p,tls:{enabled:y,acme:y&&!f&&(g.acme??!0),certPath:g.certPath,keyPath:g.keyPath,requireForAuth:g.requireForAuth??(y&&c),acmeEmail:g.acmeEmail??h[0]?.address},dkim:{enabled:C,selector:S.selector??"default",rotate:S.rotate??!1,rotateIntervalDays:S.rotateIntervalDays??90},webmail:{enabled:E,port:P.port??p.webmail,domain:I,aliases:N,tls:D,secureCookies:P.secureCookies??(!!I||D),attachmentMaxFileBytes:ce,attachmentMaxTotalBytes:q,attachmentMaxCount:J,undoSendSeconds:K},delivery:F,sesRegion:i.sesRegion??"us-east-1",accounts:h,storagePath:i.storagePath??"/var/lib/mail",maxMessageSize:i.maxMessageSize??26214400,spam:{enabled:M.enabled??c,enforce:M.enforce??!1,junkScore:M.junkScore??5,rejectScore:M.rejectScore??12,dnsbl:M.dnsbl??c,greylist:M.greylist??!1},webhookUrl:i.webhookUrl,expose:O,bindAddress:O?"0.0.0.0":"127.0.0.1"}}function Ur(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 da(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 Vo(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 le(e,n={}){let r=e.infrastructure?.compute?.proxy,i=ne(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 B(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 zo{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[a,s]of Object.entries(e)){if(s===null||s===void 0)continue;if(typeof s==="object"&&!Array.isArray(s))i+=`${r}${a}:
|
|
1
|
+
import{Y,is,kt,Dn}from"./chunk-z6xnegpe.js";import{Yt,zr}from"./chunk-7p70c4br.js";var al={};Yt(al,{default:()=>Dr,handler:()=>yt});var cl={};Yt(cl,{default:()=>Nr,handler:()=>ft});var Yl={};Yt(Yl,{EmailAnalyticsModule:()=>Je,EmailRules:()=>_t,EmailScheduling:()=>Bt,EmailSearch:()=>Ot,EmailTemplates:()=>Ce,EmailThreading:()=>$t,SharedMailboxes:()=>Ft});var Zl={};Yt(Zl,{default:()=>ra,handler:()=>na});var ed={};Yt(ed,{CallAnalytics:()=>Ut,CallRecording:()=>Vt,Callbacks:()=>at,IVRBuilder:()=>we});var td={};Yt(td,{AbTesting:()=>me,LinkTracking:()=>Zt,MmsSupport:()=>qt,SmsAnalytics:()=>jt,SmsCampaigns:()=>Ht,SmsChatbot:()=>zt});var hm={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}},ym={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 sa=".ts-cloud",Zc="TS_CLOUD_STATE_DIR",gt=null;function aa(e){gt=e?.trim()||null}function ca(){return Boolean(process.env[Zc]?.trim()||gt)}function Cn(){return process.env[Zc]?.trim()||gt||sa}function je(...e){return Ye(Cn(),...e)}function A(e,...n){let r=Cn();return pt(r)?Ye(r,...n):Ye(e,r,...n)}function la(e,n=process.cwd()){let r=(a,s)=>{let c=ur(a,s);return c===""||!c.startsWith("..")&&!pt(c)},i=pt(e)?e:Ye(n,e);return r(A(n),i)}function el(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}=el(e);return n?"serverless":"server"}function Ur(e){let{server:n,serverless:r}=el(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 eu(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??{}),a=e.sites?.main?.domain??i.find((s)=>s.domain)?.domain;if(a)return a;return`${e.project?.slug??"app"}.local`}function pr(e){let n=e.indexOf(".");return n>0?e.slice(n+1):void 0}function ne(e,n={}){let r=e.infrastructure?.compute?.managedServices?.mail,i=dr(r),a=n.environmentType??(n.environment?e.environments?.[n.environment]?.type:void 0),s=i.mode??(a==="production"?"server":"catcher"),c=s==="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.certPath&&g.keyPath),h=(i.accounts??[]).map((Q)=>({address:Q.address,password:Q.password,passwordPolicy:Q.passwordPolicy??"initial"})),S=typeof i.dkim==="object"&&i.dkim!==null?i.dkim:{},C=i.dkim===!1?!1:i.dkim===!0||c,P=typeof i.webmail==="object"&&i.webmail!==null?i.webmail:{},E=i.webmail===!1?!1:P.enabled??!0,v=d.includes(".")&&!d.endsWith(".local")&&!/^\d+\.\d+\.\d+\.\d+$/.test(d),I=P.domain===!1?void 0:P.domain??(c&&v?d:void 0),D=P.tls??(I?!1:y),N=[...new Set(P.aliases??[])].filter((Q)=>Q!==I),M=i.spam??{},F=i.delivery??(c?"direct":"none"),O=i.expose??c,G=pr(d),U=[...new Set([d,...G?[G]:[],...i.domains??[]])],ce=P.attachments?.maxFileBytes??20971520,q=P.attachments?.maxTotalBytes??20971520,J=P.attachments?.maxCount??20,K=P.undoSendSeconds??10;for(let[Q,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 ${Q} must be an integer from 0 to ${Te}`);return{enabled:eu(r),mode:s,version:i.version,hostname:d,domains:U,ports:p,tls:{enabled:y,acme:y&&!f&&(g.acme??!0),certPath:g.certPath,keyPath:g.keyPath,requireForAuth:g.requireForAuth??(y&&c),acmeEmail:g.acmeEmail??h[0]?.address},dkim:{enabled:C,selector:S.selector??"default",rotate:S.rotate??!1,rotateIntervalDays:S.rotateIntervalDays??90},webmail:{enabled:E,port:P.port??p.webmail,domain:I,aliases:N,tls:D,secureCookies:P.secureCookies??(!!I||D),attachmentMaxFileBytes:ce,attachmentMaxTotalBytes:q,attachmentMaxCount:J,undoSendSeconds:K},delivery:F,sesRegion:i.sesRegion??"us-east-1",accounts:h,storagePath:i.storagePath??"/var/lib/mail",maxMessageSize:i.maxMessageSize??26214400,spam:{enabled:M.enabled??c,enforce:M.enforce??!1,junkScore:M.junkScore??5,rejectScore:M.rejectScore??12,dnsbl:M.dnsbl??c,greylist:M.greylist??!1},webhookUrl:i.webhookUrl,expose:O,bindAddress:O?"0.0.0.0":"127.0.0.1"}}function Fr(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 da(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 qo(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 le(e,n={}){let r=e.infrastructure?.compute?.proxy,i=ne(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 B(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 Go{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[a,s]of Object.entries(e)){if(s===null||s===void 0)continue;if(typeof s==="object"&&!Array.isArray(s))i+=`${r}${a}:
|
|
2
2
|
${this.convertToYAML(s,n+1)}`;else if(Array.isArray(s)){i+=`${r}${a}:
|
|
3
3
|
`;for(let c of s)if(typeof c==="object")i+=`${r} -
|
|
4
4
|
${this.convertToYAML(c,n+2)}`;else i+=`${r} - ${c}
|
|
5
5
|
`}else i+=`${r}${a}: ${s}
|
|
6
|
-
`}return i}}function tu(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 a=Sr(e);if(a.length>0)for(let s of a)n.push({path:"Resources",message:`Circular dependency detected: ${s.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 a of i){let s=e[a];if(!/^[a-zA-Z0-9]+$/.test(a))n.push({path:`Resources.${a}`,message:"Logical ID must contain only alphanumeric characters",severity:"error"});if(!s.Type)n.push({path:`Resources.${a}.Type`,message:"Resource Type is required",severity:"error"});else if(!s.Type.startsWith("AWS::")&&!s.Type.startsWith("Custom::"))n.push({path:`Resources.${a}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(s.DeletionPolicy&&!["Delete","Retain","Snapshot"].includes(s.DeletionPolicy))n.push({path:`Resources.${a}.DeletionPolicy`,message:'DeletionPolicy must be "Delete", "Retain", or "Snapshot"',severity:"error"});if(!s.DeletionPolicy&&an(s.Type))r.push({path:`Resources.${a}.DeletionPolicy`,message:`${s.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 a of i){let s=e[a];if(!s.Type)n.push({path:`Parameters.${a}.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(s.Type&&!c.includes(s.Type))n.push({path:`Parameters.${a}.Type`,message:`Invalid parameter type: ${s.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||{},a=new Set(Object.keys(r)),s=new Set(Object.keys(i));function c(u,d){if(typeof u!=="object"||u===null)return;if(u.Ref){let m=u.Ref;if(!a.has(m)&&!s.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(!a.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=[],a=new Set,s=new Set;function c(u,d){a.add(u),s.add(u),d.push(u);let m=r.get(u)||new Set;for(let p of m)if(!a.has(p))c(p,[...d]);else if(s.has(p)){let g=d.indexOf(p),y=[...d.slice(g),p];i.push(y)}s.delete(u)}for(let u of r.keys())if(!a.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 a in i)r(i[a])}return r(e),n}function an(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 a in i){let s=i[a],c=s.Properties;if(c&&!c.Tags&&vr(s.Type))r.push({path:`Resources.${a}`,message:`Consider adding Tags to ${s.Type}`,severity:"info"});if(an(s.Type)){if(s.Type==="AWS::S3::Bucket"&&!c?.BucketEncryption)n.push({path:`Resources.${a}`,message:"S3 bucket should enable encryption",severity:"warning"});if(s.Type==="AWS::RDS::DBInstance"&&!c?.StorageEncrypted)n.push({path:`Resources.${a}`,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 ru(e){let n=[],r=[],i=[],a=Buffer.byteLength(e,"utf8"),s=a/1024,c=51200,u=460800;if(a>460800)n.push({path:"Template",message:`Template size (${s.toFixed(2)} KB) exceeds maximum size of 450 KB`,severity:"error"});else if(a>51200)r.push({path:"Template",message:`Template size (${s.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 nu(e){let n=[],r=[],i=[],a=e.Resources||{},s=e.Parameters||{},c=e.Outputs||{};if(Object.keys(a).length>500)n.push({path:"Resources",message:`Template has ${Object.keys(a).length} resources (limit is 500)`,severity:"error"});if(Object.keys(s).length>200)n.push({path:"Parameters",message:`Template has ${Object.keys(s).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 R={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})},iu={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:a,suffix:s}=e,c=[n,r,i];if(a)c.push(a);if(s)c.push(s);return c.join("-")}function o(e){return e.split("-").map((n)=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}function bm(){return Date.now().toString()}function Sm(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 ua(e,n,r,i){return r.stackName??`${e.project.slug}-${i}-${n}-site`}function pa(e,n){return`${e.project.slug}-${n}`}function ma(e,n,r,i){if(i)return i;if(r==="main")return`${e}-${n}-site`;return`${e}-${n}-${r}`}function vm(e,n,r,i){return i??`${e}-${n}-${r}`}function Cm(e,n){return`${e}-${n}-deploy`}function Oe(e,n){return`${e.project.slug}-${n}-app`}function ga(e,n){return`${e}-${n}-deployments`}function _i(e,n){return`${e}-${n}-assets`}class ou{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=(a)=>{if(n.has(a))return;if(r.has(a))throw Error(`Circular dependency detected: ${a}`);r.add(a);let s=this.nodes.get(a);if(s)for(let c of s.dependencies)i(c);r.delete(a),n.add(a),e.push(a)};for(let a of this.nodes.keys())i(a);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 Tm(e,n){let r=[],i=[],a=[],s=[],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)s.push({logicalId:g,action:"replace",resourceType:f.Type,reason:`Type changed from ${y.Type} to ${f.Type}`});else{let h=sn(y.Properties||{},f.Properties||{});if(h.length>0)if(Tr(y.Type,h))s.push({logicalId:g,action:"replace",resourceType:f.Type,changes:h,reason:"Property changes require replacement"});else a.push({logicalId:g,action:"update",resourceType:f.Type,changes:h});else c.push(g)}}let p=Rr([...i,...s,...a]);return{added:r,removed:i,updated:a,replaced:s,unchanged:c,summary:{totalChanges:r.length+i.length+a.length+s.length,requiresReplacement:s.length>0,dangerousChanges:p}}}function sn(e,n,r=""){let i=[],a=new Set([...Object.keys(e),...Object.keys(n)]);for(let s of a){let c=r?`${r}.${s}`:s,u=e[s],d=n[s];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=sn(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 a of n){let s=a.path.split(".")[0];if(i.has(s))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 Em(e){let n=[];if(n.push(`=== Stack Update Analysis ===
|
|
6
|
+
`}return i}}function tu(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 a=Sr(e);if(a.length>0)for(let s of a)n.push({path:"Resources",message:`Circular dependency detected: ${s.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 a of i){let s=e[a];if(!/^[a-zA-Z0-9]+$/.test(a))n.push({path:`Resources.${a}`,message:"Logical ID must contain only alphanumeric characters",severity:"error"});if(!s.Type)n.push({path:`Resources.${a}.Type`,message:"Resource Type is required",severity:"error"});else if(!s.Type.startsWith("AWS::")&&!s.Type.startsWith("Custom::"))n.push({path:`Resources.${a}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(s.DeletionPolicy&&!["Delete","Retain","Snapshot"].includes(s.DeletionPolicy))n.push({path:`Resources.${a}.DeletionPolicy`,message:'DeletionPolicy must be "Delete", "Retain", or "Snapshot"',severity:"error"});if(!s.DeletionPolicy&&an(s.Type))r.push({path:`Resources.${a}.DeletionPolicy`,message:`${s.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 a of i){let s=e[a];if(!s.Type)n.push({path:`Parameters.${a}.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(s.Type&&!c.includes(s.Type))n.push({path:`Parameters.${a}.Type`,message:`Invalid parameter type: ${s.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||{},a=new Set(Object.keys(r)),s=new Set(Object.keys(i));function c(u,d){if(typeof u!=="object"||u===null)return;if(u.Ref){let m=u.Ref;if(!a.has(m)&&!s.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(!a.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=[],a=new Set,s=new Set;function c(u,d){a.add(u),s.add(u),d.push(u);let m=r.get(u)||new Set;for(let p of m)if(!a.has(p))c(p,[...d]);else if(s.has(p)){let g=d.indexOf(p),y=[...d.slice(g),p];i.push(y)}s.delete(u)}for(let u of r.keys())if(!a.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 a in i)r(i[a])}return r(e),n}function an(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 a in i){let s=i[a],c=s.Properties;if(c&&!c.Tags&&vr(s.Type))r.push({path:`Resources.${a}`,message:`Consider adding Tags to ${s.Type}`,severity:"info"});if(an(s.Type)){if(s.Type==="AWS::S3::Bucket"&&!c?.BucketEncryption)n.push({path:`Resources.${a}`,message:"S3 bucket should enable encryption",severity:"warning"});if(s.Type==="AWS::RDS::DBInstance"&&!c?.StorageEncrypted)n.push({path:`Resources.${a}`,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 ru(e){let n=[],r=[],i=[],a=Buffer.byteLength(e,"utf8"),s=a/1024,c=51200,u=460800;if(a>460800)n.push({path:"Template",message:`Template size (${s.toFixed(2)} KB) exceeds maximum size of 450 KB`,severity:"error"});else if(a>51200)r.push({path:"Template",message:`Template size (${s.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 nu(e){let n=[],r=[],i=[],a=e.Resources||{},s=e.Parameters||{},c=e.Outputs||{};if(Object.keys(a).length>500)n.push({path:"Resources",message:`Template has ${Object.keys(a).length} resources (limit is 500)`,severity:"error"});if(Object.keys(s).length>200)n.push({path:"Parameters",message:`Template has ${Object.keys(s).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 R={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})},iu={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:a,suffix:s}=e,c=[n,r,i];if(a)c.push(a);if(s)c.push(s);return c.join("-")}function o(e){return e.split("-").map((n)=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}function bm(){return Date.now().toString()}function Sm(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 ua(e,n,r,i){return r.stackName??`${e.project.slug}-${i}-${n}-site`}function pa(e,n){return`${e.project.slug}-${n}`}function ma(e,n,r,i){if(i)return i;if(r==="main")return`${e}-${n}-site`;return`${e}-${n}-${r}`}function vm(e,n,r,i){return i??`${e}-${n}-${r}`}function Cm(e,n){return`${e}-${n}-deploy`}function Oe(e,n){return`${e.project.slug}-${n}-app`}function ga(e,n){return`${e}-${n}-deployments`}function Li(e,n){return`${e}-${n}-assets`}class ou{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=(a)=>{if(n.has(a))return;if(r.has(a))throw Error(`Circular dependency detected: ${a}`);r.add(a);let s=this.nodes.get(a);if(s)for(let c of s.dependencies)i(c);r.delete(a),n.add(a),e.push(a)};for(let a of this.nodes.keys())i(a);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 Tm(e,n){let r=[],i=[],a=[],s=[],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)s.push({logicalId:g,action:"replace",resourceType:f.Type,reason:`Type changed from ${y.Type} to ${f.Type}`});else{let h=sn(y.Properties||{},f.Properties||{});if(h.length>0)if(Tr(y.Type,h))s.push({logicalId:g,action:"replace",resourceType:f.Type,changes:h,reason:"Property changes require replacement"});else a.push({logicalId:g,action:"update",resourceType:f.Type,changes:h});else c.push(g)}}let p=Rr([...i,...s,...a]);return{added:r,removed:i,updated:a,replaced:s,unchanged:c,summary:{totalChanges:r.length+i.length+a.length+s.length,requiresReplacement:s.length>0,dangerousChanges:p}}}function sn(e,n,r=""){let i=[],a=new Set([...Object.keys(e),...Object.keys(n)]);for(let s of a){let c=r?`${r}.${s}`:s,u=e[s],d=n[s];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=sn(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 a of n){let s=a.path.split(".")[0];if(i.has(s))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 Em(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"}
|
|
@@ -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)=>At.generateBunDockerfile({serverPath:e,port:n}),bunWithBuild:(e,n,r=3000)=>At.generateBunDockerfile({serverPath:e,port:r,buildCommands:[n]}),bunFullStack:(e,n=3000)=>At.generateBunDockerfile({serverPath:e,port:n,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,n=3000)=>At.generateBunDockerfile({serverPath:e,port:n,healthCheckEndpoint:"/api/health"})}}var fa=[400,403,404,416,429,500,502,503,504],tl=[500,502,503,504],rl=["GET","HEAD","OPTIONS"],wm="-failover-group",nl=["default","media-quality-based"],il={min:1,max:3},ol={min:1,max:10};function Ho(e){if(e===void 0)return[...tl];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${fa.join(", ")}). Omit it to use the default ${tl.join(", ")}.`);let n=e.filter((r)=>!fa.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: ${fa.join(", ")}.`);return[...new Set(e)].sort((r,i)=>r-i)}function ha(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=Ho(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(!nl.includes(e))throw Error(`CloudFront origin failover: ${n} has selection criteria ${JSON.stringify(e)}. Allowed: ${nl.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 nt(e,n="the origin"){let r={};if(e?.connectionAttempts!==void 0)Ze(e.connectionAttempts,il,`${n} connectionAttempts`),r.ConnectionAttempts=e.connectionAttempts;if(e?.connectionTimeout!==void 0)Ze(e.connectionTimeout,ol,`${n} connectionTimeout (seconds)`),r.ConnectionTimeout=e.connectionTimeout;return r}function qo(e){return{Quantity:1,Items:[ha(e)]}}function Cn(e,n="the cache behavior"){let i=(Array.isArray(e)?e:e?.Items??[]).filter((a)=>!rl.includes(a.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 ${rl.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function Oi(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}function _e(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 Tn(e,n="the distribution"){let r=_e(e.Origins),i=new Set(r.map((p)=>se(p.Id)).filter((p)=>!!p)),a=new Map(r.map((p)=>[se(p.Id)??"",p.DomainName])),s=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,il,`${n} origin "${g}" ConnectionAttempts`);if(p.ConnectionTimeout!==void 0)Ze(p.ConnectionTimeout,ol,`${n} origin "${g}" ConnectionTimeout (seconds)`)}let c=e.OriginGroups,u=_e(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=_e(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((E)=>se(E.OriginId));for(let E of S)if(E&&!i.has(E)&&!s)throw Error(`CloudFront origin failover: ${y} lists member "${E}", 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 C=p.FailoverCriteria?.StatusCodes,P=_e(C);if(Ho(P),C?.Quantity!==void 0&&C.Quantity!==P.length)throw Error(`CloudFront origin failover: ${y} FailoverCriteria.StatusCodes.Quantity is ${C.Quantity} but it lists ${P.length} code(s).`);if(on(p.SelectionCriteria,y),p.SelectionCriteria==="media-quality-based")for(let E of S){let v=E?se(a.get(E)):void 0;if(v&&!Er.test(v))throw Error(`CloudFront origin failover: ${y} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${E}" is ${v}. Use 'default'.`)}}let m=[];if(e.DefaultCacheBehavior)m.push({behavior:e.DefaultCacheBehavior,name:"the default cache behavior"});for(let p of _e(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))Cn(p.AllowedMethods??["GET","HEAD"],`${g} of ${n} (origin group "${y}")`);else if(!i.has(y)&&!s&&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 ze{static createDistribution(e){let{slug:n,environment:r,origin:i,customDomain:a,certificateArn:s,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||"",...nt(i,"the CDN origin")},S;if(i.type==="s3"){let P=`${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=R.Ref(P)}else if(i.type==="alb"||i.type==="custom")h.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let C={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(a&&s)C.Properties.DistributionConfig.Aliases=[a],C.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(c&&c.length>0)C.Properties.DistributionConfig.CustomErrorResponses=c.map((P)=>({ErrorCode:P.errorCode,ResponseCode:P.responseCode,ResponsePagePath:P.responsePagePath}));if(d&&d.length>0)C.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=d.map((P)=>({EventType:P.event,LambdaFunctionARN:P.functionArn}));if(g)ze.addOriginFailover(C,g);return{distribution:C,originAccessControl:S,logicalId:f}}static addOriginFailover(e,n){let r=e.Properties.DistributionConfig,i=r.DefaultCacheBehavior,a=i.TargetOriginId,s=n.id??"FailoverOrigin";if(r.OriginGroups&&r.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(Cn(i.AllowedMethods??["GET","HEAD"],"the default cache behavior"),r.Origins.some((p)=>p.Id===s))throw Error(`CloudFront origin failover: an origin with id "${s}" already exists`);let c=ha({primaryOriginId:a,secondaryOriginId:s,statusCodes:n.statusCodes,selectionCriteria:n.selectionCriteria}),u=n.type??(Oi(n.domainName)?"s3":"custom"),d={Id:s,DomainName:n.domainName,OriginPath:n.originPath||"",...nt(n,"the failover origin")},m=nt(n.primary,"the primary origin");if(Object.keys(m).length>0){let p=r.Origins.find((g)=>g.Id===a);if(p)Object.assign(p,m)}if(u==="s3"){let p=r.Origins.find((g)=>g.Id===a);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,Tn(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 ze.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"}),a=o(i),s=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)=>At.generateBunDockerfile({serverPath:e,port:n}),bunWithBuild:(e,n,r=3000)=>At.generateBunDockerfile({serverPath:e,port:r,buildCommands:[n]}),bunFullStack:(e,n=3000)=>At.generateBunDockerfile({serverPath:e,port:n,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(e,n=3000)=>At.generateBunDockerfile({serverPath:e,port:n,healthCheckEndpoint:"/api/health"})}}var fa=[400,403,404,416,429,500,502,503,504],tl=[500,502,503,504],rl=["GET","HEAD","OPTIONS"],wm="-failover-group",nl=["default","media-quality-based"],il={min:1,max:3},ol={min:1,max:10};function Wo(e){if(e===void 0)return[...tl];if(e.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${fa.join(", ")}). Omit it to use the default ${tl.join(", ")}.`);let n=e.filter((r)=>!fa.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: ${fa.join(", ")}.`);return[...new Set(e)].sort((r,i)=>r-i)}function ha(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=Wo(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(!nl.includes(e))throw Error(`CloudFront origin failover: ${n} has selection criteria ${JSON.stringify(e)}. Allowed: ${nl.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 it(e,n="the origin"){let r={};if(e?.connectionAttempts!==void 0)Ze(e.connectionAttempts,il,`${n} connectionAttempts`),r.ConnectionAttempts=e.connectionAttempts;if(e?.connectionTimeout!==void 0)Ze(e.connectionTimeout,ol,`${n} connectionTimeout (seconds)`),r.ConnectionTimeout=e.connectionTimeout;return r}function Ko(e){return{Quantity:1,Items:[ha(e)]}}function Tn(e,n="the cache behavior"){let i=(Array.isArray(e)?e:e?.Items??[]).filter((a)=>!rl.includes(a.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 ${rl.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function Mi(e){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(e)&&!/s3-website/i.test(e)}function _e(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 En(e,n="the distribution"){let r=_e(e.Origins),i=new Set(r.map((p)=>se(p.Id)).filter((p)=>!!p)),a=new Map(r.map((p)=>[se(p.Id)??"",p.DomainName])),s=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,il,`${n} origin "${g}" ConnectionAttempts`);if(p.ConnectionTimeout!==void 0)Ze(p.ConnectionTimeout,ol,`${n} origin "${g}" ConnectionTimeout (seconds)`)}let c=e.OriginGroups,u=_e(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=_e(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((E)=>se(E.OriginId));for(let E of S)if(E&&!i.has(E)&&!s)throw Error(`CloudFront origin failover: ${y} lists member "${E}", 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 C=p.FailoverCriteria?.StatusCodes,P=_e(C);if(Wo(P),C?.Quantity!==void 0&&C.Quantity!==P.length)throw Error(`CloudFront origin failover: ${y} FailoverCriteria.StatusCodes.Quantity is ${C.Quantity} but it lists ${P.length} code(s).`);if(on(p.SelectionCriteria,y),p.SelectionCriteria==="media-quality-based")for(let E of S){let v=E?se(a.get(E)):void 0;if(v&&!Er.test(v))throw Error(`CloudFront origin failover: ${y} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${E}" is ${v}. Use 'default'.`)}}let m=[];if(e.DefaultCacheBehavior)m.push({behavior:e.DefaultCacheBehavior,name:"the default cache behavior"});for(let p of _e(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))Tn(p.AllowedMethods??["GET","HEAD"],`${g} of ${n} (origin group "${y}")`);else if(!i.has(y)&&!s&&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 ze{static createDistribution(e){let{slug:n,environment:r,origin:i,customDomain:a,certificateArn:s,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||"",...it(i,"the CDN origin")},S;if(i.type==="s3"){let P=`${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=R.Ref(P)}else if(i.type==="alb"||i.type==="custom")h.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let C={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(a&&s)C.Properties.DistributionConfig.Aliases=[a],C.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(c&&c.length>0)C.Properties.DistributionConfig.CustomErrorResponses=c.map((P)=>({ErrorCode:P.errorCode,ResponseCode:P.responseCode,ResponsePagePath:P.responsePagePath}));if(d&&d.length>0)C.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=d.map((P)=>({EventType:P.event,LambdaFunctionARN:P.functionArn}));if(g)ze.addOriginFailover(C,g);return{distribution:C,originAccessControl:S,logicalId:f}}static addOriginFailover(e,n){let r=e.Properties.DistributionConfig,i=r.DefaultCacheBehavior,a=i.TargetOriginId,s=n.id??"FailoverOrigin";if(r.OriginGroups&&r.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(Tn(i.AllowedMethods??["GET","HEAD"],"the default cache behavior"),r.Origins.some((p)=>p.Id===s))throw Error(`CloudFront origin failover: an origin with id "${s}" already exists`);let c=ha({primaryOriginId:a,secondaryOriginId:s,statusCodes:n.statusCodes,selectionCriteria:n.selectionCriteria}),u=n.type??(Mi(n.domainName)?"s3":"custom"),d={Id:s,DomainName:n.domainName,OriginPath:n.originPath||"",...it(n,"the failover origin")},m=it(n.primary,"the primary origin");if(Object.keys(m).length>0){let p=r.Origins.find((g)=>g.Id===a);if(p)Object.assign(p,m)}if(u==="s3"){let p=r.Origins.find((g)=>g.Id===a);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,En(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 ze.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"}),a=o(i),s=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) => {
|
|
@@ -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:a="GET_HEAD",cachedMethods:s="GET_HEAD",compress:c=!0,forwardQueryString:u=!0,forwardHeaders:d=[]}=e;return{MinTTL:n.min,MaxTTL:n.max,DefaultTTL:n.default,Compress:c,AllowedMethods:ze.Config.allowedMethods(a),CachedMethods:ze.Config.cachedMethods(s),ForwardedValues:{QueryString:u,Headers:d,Cookies:ze.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=ze.Config.allowedMethods(n.allowedMethods);if(n.cachedMethods)r.CachedMethods=ze.Config.cachedMethods(n.cachedMethods);if(n.cookies){if(!r.ForwardedValues)r.ForwardedValues={QueryString:!0};r.ForwardedValues.Cookies=ze.Config.cookies(n.cookies,n.allowedCookies)}return e}}var su=[403,404,500,502,503,504],Go="TsCloud::StorageFailover",Wo="AllowCloudFrontFailoverRead",wr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,Ir=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function ya(e){let{failover:n,primaryBucket:r,primaryRegion:i}=e,a=e.where??"storage failover";if(!n||typeof n!=="object")throw Error(`${a}.failover must be an object such as { region: 'us-west-2' }.`);if(!n.region||!wr.test(n.region))throw Error(`${a}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(n.region)}.`);if(n.region===i)throw Error(`${a}.failover.region is ${n.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let s=n.bucket??`${r}-${n.region}`;if(!Ir.test(s)||s.includes("..")){let c=n.bucket===void 0&&s.length>63?` The default name (<primary bucket>-<region>) is ${s.length} characters; S3 allows 63. Set ${a}.failover.bucket.`:"";throw Error(`${a}.failover: "${s}" is not a valid S3 bucket name.${c}`)}if(s===r)throw Error(`${a}.failover.bucket must differ from the primary bucket "${r}".`);return{replicaBucket:s,replicaRegion:n.region,replicate:n.replicate!==!1,statusCodes:Ho(n.statusCodes??su),primaryConnection:nt(n,`${a}.failover`)}}function ba(e,n){return`${e}.s3.${n}.amazonaws.com`}function Sa(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 va(e){return{Role:e.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${e.replicaBucket}`}}]}}function Ca(e){return{Sid:Wo,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function Ta(e){let r=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[Go];return Array.isArray(r)?r:[]}class Ae{static createHostedZone(e){let{domain:n,slug:r,environment:i,comment:a}=e,s=l({slug:r,environment:i,resourceType:"hostedzone"}),c=o(`${s}-${n.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:n,HostedZoneConfig:{Comment:a||`Hosted zone for ${n}`}}},logicalId:c}}static createRecord(e){let{hostedZoneId:n,hostedZoneName:r,name:i,type:a,ttl:s,values:c,aliasTarget:u}=e,d=o(`record-${i.replace(/\./g,"")}-${a}`),m={Type:"AWS::Route53::RecordSet",Properties:{Name:i,Type:a}};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=s||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((a)=>`${a.priority} ${a.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 a=`v=DMARC1; p=${n}; rua=mailto:${r}`;return Ae.createTxtRecord(`_dmarc.${e}`,a,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:a,validationMethod:s="DNS",hostedZoneId:c}=e,u=l({slug:i,environment:a,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:s}};if(s==="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:a=!0,multiRegion:s=!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:R.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:a,KeyPolicy:d,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:s}},p=o(`${c}-alias`),g={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${r}-${i}`,TargetKeyId:R.Ref(u)}};return{key:m,alias:g,logicalId:u,aliasId:p}}static createFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",defaultAction:a="allow"}=e,s=l({slug:n,environment:r,resourceType:"waf"}),c=o(s);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:s,Scope:i,DefaultAction:a==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${n} ${r}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-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 a=l({slug:r,environment:i,resourceType:"ipset"}),s=o(`${a}-${n.name}`),c={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${a}-${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:R.GetAtt(s,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),{webAcl:e,ipSet:c,ipSetLogicalId:s}}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:a=10}=n;return j.setPathRateLimit(e,{name:"LoginRateLimit",priority:i,requestsPerWindow:a*5,paths:r}),e}static protectApiEndpoints(e,n){let{apiPaths:r,priority:i,requestsPerMinute:a=100}=n;return j.setPathRateLimit(e,{name:"ApiRateLimit",priority:i,requestsPerWindow:a*5,paths:r}),e}static createProtectedFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",enableBotControl:a=!1,enableRateLimiting:s=!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}),a)u=j.addManagedRules(u,{name:"AWSBotControl",priority:m++,...j.ManagedRuleGroups.BotControl});if(s)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 au(e){let n=e.split(".")[0]??"";return n==="a1"||/^[a-z]+\d+g[a-z]*$/.test(n)}function cu(e="t3.micro"){return`/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${au(e)?"arm64":"x86_64"}`}function sl(e="t3.micro"){return`{{resolve:ssm:${cu(e)}}}`}class b{static createServer(e){let{slug:n,environment:r,instanceType:i="t3.micro",imageId:a=sl(i),keyName:s,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:a,InstanceType:i,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(s)h.Properties.KeyName=s;if(c)h.Properties.SecurityGroupIds=c;if(u)h.Properties.SubnetId=u;if(d)h.Properties.UserData=R.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:a,ingress:s=[],egress:c=[]}=e,u=l({slug:n,environment:r,resourceType:"sg"}),d=o(u),m={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:a||`Security group for ${n} ${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(i)m.Properties.VpcId=i;if(s.length>0)m.Properties.SecurityGroupIngress=s.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:a,securityGroups:s,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:a,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(s)m.Properties.SecurityGroups=s;return{loadBalancer:m,logicalId:d}}static createTargetGroup(e){let{slug:n,environment:r,port:i,protocol:a="HTTP",vpcId:s,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:a,VpcId:s,TargetType:c,HealthCheckEnabled:!0,HealthCheckProtocol:a,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:a,defaultTargetGroupArn:s}=n,c=o(`listener-${e}-${r}`),u={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:R.Ref(e),Port:r,Protocol:i,DefaultActions:[{Type:"forward",TargetGroupArn:s}]}};if(i==="HTTPS"&&a)u.Properties.Certificates=[{CertificateArn:a}],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:a="256",memory:s="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:C}=b.createEcsCluster(n,r),P=l({slug:n,environment:r,resourceType:"fargate"}),E=o(`${P}-execution-role`),v={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]}},I=o(`${P}-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"}]}}},N=o(`${P}-task`),M={Type:"AWS::ECS::TaskDefinition",Properties:{Family:P,TaskRoleArn:R.GetAtt(I,"Arn"),ExecutionRoleArn:R.GetAtt(E,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:a,Memory:s,ContainerDefinitions:[{Name:n,Image:i,Essential:!0,PortMappings:[{ContainerPort:u,Protocol:"tcp"}],Environment:Object.entries(d).map(([G,U])=>({Name:G,Value:U})),Secrets:m.map((G)=>({Name:G.name,ValueFrom:G.valueFrom}))}],Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}};if(p)M.Properties.ContainerDefinitions[0].HealthCheck={Command:p.command,Interval:p.interval||30,Timeout:p.timeout||5,Retries:p.retries||3,StartPeriod:60};if(g)M.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":g,"awslogs-region":R.Ref("AWS::Region"),"awslogs-stream-prefix":n}};let F=o(`${P}-service`),O={Type:"AWS::ECS::Service",Properties:{ServiceName:P,Cluster:R.Ref(C),TaskDefinition:R.Ref(N),DesiredCount:c,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:y,SecurityGroups:f,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}};if(h)O.Properties.LoadBalancers=[{TargetGroupArn:h,ContainerName:n,ContainerPort:u}];return{cluster:S,taskDefinition:M,service:O,taskRole:D,executionRole:v,clusterLogicalId:C,taskDefinitionLogicalId:N,serviceLogicalId:F,taskRoleLogicalId:I,executionRoleLogicalId:E}}static createLambdaFunction(e){let{slug:n,environment:r,runtime:i,handler:a,code:s,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:R.GetAtt(y,"Arn"),Handler:a,Code:{...s.s3Bucket&&{S3Bucket:s.s3Bucket},...s.s3Key&&{S3Key:s.s3Key},...s.zipFile&&{ZipFile:s.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,a=Object.entries(i).map(([s,c])=>`echo "export ${s}='${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:a="GET_HEAD",cachedMethods:s="GET_HEAD",compress:c=!0,forwardQueryString:u=!0,forwardHeaders:d=[]}=e;return{MinTTL:n.min,MaxTTL:n.max,DefaultTTL:n.default,Compress:c,AllowedMethods:ze.Config.allowedMethods(a),CachedMethods:ze.Config.cachedMethods(s),ForwardedValues:{QueryString:u,Headers:d,Cookies:ze.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=ze.Config.allowedMethods(n.allowedMethods);if(n.cachedMethods)r.CachedMethods=ze.Config.cachedMethods(n.cachedMethods);if(n.cookies){if(!r.ForwardedValues)r.ForwardedValues={QueryString:!0};r.ForwardedValues.Cookies=ze.Config.cookies(n.cookies,n.allowedCookies)}return e}}var su=[403,404,500,502,503,504],Jo="TsCloud::StorageFailover",Xo="AllowCloudFrontFailoverRead",wr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,Ir=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function ya(e){let{failover:n,primaryBucket:r,primaryRegion:i}=e,a=e.where??"storage failover";if(!n||typeof n!=="object")throw Error(`${a}.failover must be an object such as { region: 'us-west-2' }.`);if(!n.region||!wr.test(n.region))throw Error(`${a}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(n.region)}.`);if(n.region===i)throw Error(`${a}.failover.region is ${n.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let s=n.bucket??`${r}-${n.region}`;if(!Ir.test(s)||s.includes("..")){let c=n.bucket===void 0&&s.length>63?` The default name (<primary bucket>-<region>) is ${s.length} characters; S3 allows 63. Set ${a}.failover.bucket.`:"";throw Error(`${a}.failover: "${s}" is not a valid S3 bucket name.${c}`)}if(s===r)throw Error(`${a}.failover.bucket must differ from the primary bucket "${r}".`);return{replicaBucket:s,replicaRegion:n.region,replicate:n.replicate!==!1,statusCodes:Wo(n.statusCodes??su),primaryConnection:it(n,`${a}.failover`)}}function ba(e,n){return`${e}.s3.${n}.amazonaws.com`}function Sa(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 va(e){return{Role:e.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${e.replicaBucket}`}}]}}function Ca(e){return{Sid:Xo,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${e.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":e.distributionArn}}}}function Ta(e){let r=(typeof e==="string"?JSON.parse(e):e)?.Metadata?.[Jo];return Array.isArray(r)?r:[]}class Ae{static createHostedZone(e){let{domain:n,slug:r,environment:i,comment:a}=e,s=l({slug:r,environment:i,resourceType:"hostedzone"}),c=o(`${s}-${n.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:n,HostedZoneConfig:{Comment:a||`Hosted zone for ${n}`}}},logicalId:c}}static createRecord(e){let{hostedZoneId:n,hostedZoneName:r,name:i,type:a,ttl:s,values:c,aliasTarget:u}=e,d=o(`record-${i.replace(/\./g,"")}-${a}`),m={Type:"AWS::Route53::RecordSet",Properties:{Name:i,Type:a}};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=s||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((a)=>`${a.priority} ${a.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 a=`v=DMARC1; p=${n}; rua=mailto:${r}`;return Ae.createTxtRecord(`_dmarc.${e}`,a,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:a,validationMethod:s="DNS",hostedZoneId:c}=e,u=l({slug:i,environment:a,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:s}};if(s==="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:a=!0,multiRegion:s=!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:R.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:a,KeyPolicy:d,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:s}},p=o(`${c}-alias`),g={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${r}-${i}`,TargetKeyId:R.Ref(u)}};return{key:m,alias:g,logicalId:u,aliasId:p}}static createFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",defaultAction:a="allow"}=e,s=l({slug:n,environment:r,resourceType:"waf"}),c=o(s);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:s,Scope:i,DefaultAction:a==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${n} ${r}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${s}-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 a=l({slug:r,environment:i,resourceType:"ipset"}),s=o(`${a}-${n.name}`),c={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${a}-${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:R.GetAtt(s,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${n.name}-metric`}}),{webAcl:e,ipSet:c,ipSetLogicalId:s}}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:a=10}=n;return j.setPathRateLimit(e,{name:"LoginRateLimit",priority:i,requestsPerWindow:a*5,paths:r}),e}static protectApiEndpoints(e,n){let{apiPaths:r,priority:i,requestsPerMinute:a=100}=n;return j.setPathRateLimit(e,{name:"ApiRateLimit",priority:i,requestsPerWindow:a*5,paths:r}),e}static createProtectedFirewall(e){let{slug:n,environment:r,scope:i="CLOUDFRONT",enableBotControl:a=!1,enableRateLimiting:s=!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}),a)u=j.addManagedRules(u,{name:"AWSBotControl",priority:m++,...j.ManagedRuleGroups.BotControl});if(s)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 au(e){let n=e.split(".")[0]??"";return n==="a1"||/^[a-z]+\d+g[a-z]*$/.test(n)}function cu(e="t3.micro"){return`/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-${au(e)?"arm64":"x86_64"}`}function sl(e="t3.micro"){return`{{resolve:ssm:${cu(e)}}}`}class b{static createServer(e){let{slug:n,environment:r,instanceType:i="t3.micro",imageId:a=sl(i),keyName:s,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:a,InstanceType:i,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(s)h.Properties.KeyName=s;if(c)h.Properties.SecurityGroupIds=c;if(u)h.Properties.SubnetId=u;if(d)h.Properties.UserData=R.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:a,ingress:s=[],egress:c=[]}=e,u=l({slug:n,environment:r,resourceType:"sg"}),d=o(u),m={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:a||`Security group for ${n} ${r}`,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(i)m.Properties.VpcId=i;if(s.length>0)m.Properties.SecurityGroupIngress=s.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:a,securityGroups:s,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:a,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(s)m.Properties.SecurityGroups=s;return{loadBalancer:m,logicalId:d}}static createTargetGroup(e){let{slug:n,environment:r,port:i,protocol:a="HTTP",vpcId:s,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:a,VpcId:s,TargetType:c,HealthCheckEnabled:!0,HealthCheckProtocol:a,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:a,defaultTargetGroupArn:s}=n,c=o(`listener-${e}-${r}`),u={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:R.Ref(e),Port:r,Protocol:i,DefaultActions:[{Type:"forward",TargetGroupArn:s}]}};if(i==="HTTPS"&&a)u.Properties.Certificates=[{CertificateArn:a}],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:a="256",memory:s="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:C}=b.createEcsCluster(n,r),P=l({slug:n,environment:r,resourceType:"fargate"}),E=o(`${P}-execution-role`),v={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]}},I=o(`${P}-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"}]}}},N=o(`${P}-task`),M={Type:"AWS::ECS::TaskDefinition",Properties:{Family:P,TaskRoleArn:R.GetAtt(I,"Arn"),ExecutionRoleArn:R.GetAtt(E,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:a,Memory:s,ContainerDefinitions:[{Name:n,Image:i,Essential:!0,PortMappings:[{ContainerPort:u,Protocol:"tcp"}],Environment:Object.entries(d).map(([G,U])=>({Name:G,Value:U})),Secrets:m.map((G)=>({Name:G.name,ValueFrom:G.valueFrom}))}],Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}};if(p)M.Properties.ContainerDefinitions[0].HealthCheck={Command:p.command,Interval:p.interval||30,Timeout:p.timeout||5,Retries:p.retries||3,StartPeriod:60};if(g)M.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":g,"awslogs-region":R.Ref("AWS::Region"),"awslogs-stream-prefix":n}};let F=o(`${P}-service`),O={Type:"AWS::ECS::Service",Properties:{ServiceName:P,Cluster:R.Ref(C),TaskDefinition:R.Ref(N),DesiredCount:c,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:y,SecurityGroups:f,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}};if(h)O.Properties.LoadBalancers=[{TargetGroupArn:h,ContainerName:n,ContainerPort:u}];return{cluster:S,taskDefinition:M,service:O,taskRole:D,executionRole:v,clusterLogicalId:C,taskDefinitionLogicalId:N,serviceLogicalId:F,taskRoleLogicalId:I,executionRoleLogicalId:E}}static createLambdaFunction(e){let{slug:n,environment:r,runtime:i,handler:a,code:s,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:R.GetAtt(y,"Arn"),Handler:a,Code:{...s.s3Bucket&&{S3Bucket:s.s3Bucket},...s.s3Key&&{S3Key:s.s3Key},...s.zipFile&&{ZipFile:s.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,a=Object.entries(i).map(([s,c])=>`echo "export ${s}='${c}'" >> /etc/environment`).join(`
|
|
201
201
|
`);return`#!/bin/bash
|
|
202
202
|
# Update system
|
|
203
203
|
yum update -y
|
|
@@ -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 it{static createFileSystem(e){let{slug:n,environment:r,encrypted:i=!0,kmsKeyId:a,performanceMode:s="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:s,ThroughputMode:c,FileSystemTags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(a)g.Properties.KmsKeyId=a;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:a,securityGroups:s,ipAddress:c}=n,u=l({slug:r,environment:i,resourceType:"efs-mt"}),d=o(`${u}-${a}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:R.Ref(e),SubnetId:a,SecurityGroups:s}};if(c)m.Properties.IpAddress=c;return{mountTarget:m,logicalId:d}}static createAccessPoint(e,n){let{slug:r,environment:i,path:a="/",uid:s="1000",gid:c="1000",permissions:u="755"}=n,d=l({slug:r,environment:i,resourceType:"efs-ap"}),m=o(`${d}-${a.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:R.Ref(e),PosixUser:{Uid:s,Gid:c},RootDirectory:{Path:a,CreationInfo:{OwnerUid:s,OwnerGid:c,Permissions:u}},AccessPointTags:[{Key:"Name",Value:`${d}-${a}`},{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 a=`AFTER_${r}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:a})}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:a=[],sourceCidrBlocks:s=[],description:c}=e,u=l({slug:n,environment:r,resourceType:"efs-sg"}),d=o(u),m=[];for(let g of a)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:g,Description:"NFS from security group"});for(let g of s)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:a,securityGroupId:s}=n,c=[],u=[];for(let d=0;d<a.length;d++){let m=a[d],p=l({slug:r,environment:i,resourceType:"efs-mt"}),g=o(`${p}-az${d+1}`),y={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:R.Ref(e),SubnetId:m,SecurityGroups:[s]}};c.push(y),u.push(g)}return{mountTargets:c,logicalIds:u}}static createCompleteFileSystem(e){let{slug:n,environment:r,vpcId:i,subnetIds:a,sourceSecurityGroupIds:s=[],encrypted:c=!0,performanceMode:u="generalPurpose",throughputMode:d="elastic",enableBackup:m=!0,transitionToIA:p}=e,g={},{fileSystem:y,logicalId:f}=it.createFileSystem({slug:n,environment:r,encrypted:c,performanceMode:u,throughputMode:d,enableBackup:m});if(p)it.setLifecyclePolicy(y,{transitionToIA:p,transitionToPrimary:!0});g[f]=y;let{securityGroup:h,logicalId:S}=it.createEfsSecurityGroup({slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:s});g[S]=h;let{mountTargets:C,logicalIds:P}=it.createMultiAzMountTargets(f,{slug:n,environment:r,subnetIds:a,securityGroupId:R.Ref(S)});for(let E=0;E<C.length;E++)g[P[E]]=C[E];return{resources:g,outputs:{fileSystemId:f,securityGroupId:S,mountTargetIds:P}}}}class k{static verifyDomain(e){let{domain:n,slug:r,environment:i,enableDkim:a=!0,dkimKeyLength:s="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(a)d.Properties.DkimSigningAttributes={NextSigningKeyLength:s};return{emailIdentity:d,logicalId:u}}static createDkimRecords(e,n,r){let i=[];for(let a=0;a<n.length;a++){let s=n[a],c=o(`dkim-${e.replace(/\./g,"")}-${a+1}`),u={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`${s}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${s}.dkim.amazonses.com`]}};i.push({record:u,logicalId:c})}return i}static createConfigurationSet(e){let{slug:n,environment:r,name:i,reputationMetrics:a=!0,sendingEnabled:s=!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:a},SendingOptions:{SendingEnabled:s},SuppressionOptions:{SuppressedReasons:p}}},logicalId:m}}static createReceiptRuleSet(e){let{slug:n,environment:r,name:i}=e,a=i||l({slug:n,environment:r,resourceType:"ses-ruleset"}),s=o(a);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:a}},logicalId:s}}static createReceiptRule(e,n){let{slug:r,environment:i,ruleSetName:a,recipients:s,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:a,Rule:{Name:y,Enabled:c,ScanEnabled:u,TlsPolicy:d,Recipients:s,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:a=!1}=r||{},s=o(`spf-${e.replace(/\./g,"")}`),c="v=spf1 include:amazonses.com";for(let d of i)c+=` include:${d}`;return c+=a?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${c}"`]}},logicalId:s}}static createDmarcRecord(e,n,r){let{policy:i="none",subdomainPolicy:a,percentage:s=100,reportingEmail:c,forensicEmail:u}=r||{},d=o(`dmarc-${e.replace(/\./g,"")}`),m=`v=DMARC1; p=${i}; pct=${s}`;if(a)m+=`; sp=${a}`;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:a,s3KeyPrefix:s="inbound/",region:c,hostedZoneId:u,lambdaFunctionArn:d,snsTopicArn:m}=e,p={},{ruleSet:g,logicalId:y}=k.createReceiptRuleSet({slug:n,environment:r});p[y]=g;let{receiptRule:f,logicalId:h}=k.createReceiptRule(y,{slug:n,environment:r,ruleSetName:g.Properties.RuleSetName||`${n}-${r}-receipt-rule-set`,recipients:[i],s3Action:{bucketName:a,prefix:s},lambdaAction:d?{functionArn:d,invocationType:"Event"}:void 0,snsAction:m?{topicArn:m}:void 0});p[h]=f;let{record:S,logicalId:C}=k.createMxRecord(i,u,c);return p[C]=S,{resources:p,outputs:{ruleSetLogicalId:y,ruleLogicalId:h,mxRecordLogicalId:C}}}static createCompleteDomainSetup(e){let{slug:n,environment:r,domain:i,hostedZoneId:a,region:s,enableInbound:c=!1,inboundS3Bucket:u,dmarcReportingEmail:d}=e,m={},{emailIdentity:p,logicalId:g}=k.verifyDomain({domain:i,slug:n,environment:r});m[g]=p;let{configurationSet:y,logicalId:f}=k.createConfigurationSet({slug:n,environment:r});m[f]=y;let{record:h,logicalId:S}=k.createSpfRecord(i,a);m[S]=h;let{record:C,logicalId:P}=k.createDmarcRecord(i,a,{policy:"none",reportingEmail:d||`dmarc-reports@${i}`});if(m[P]=C,c&&u){let E=k.createInboundEmailSetup({slug:n,environment:r,domain:i,s3BucketName:u,region:s,hostedZoneId:a});Object.assign(m,E.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 k.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:n,environment:r,s3BucketArn:i,sesIdentityArn:a}=e,s=l({slug:n,environment:r,resourceType:"email-lambda-role"}),c=o(s),u=o(`${s}-policy`),d={Type:"AWS::IAM::Role",Properties:{RoleName:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},m=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[i,`${i}/*`]}];if(a)m.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:a});let p={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${s}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:m},Roles:[R.Ref(c)]}};return{role:d,policy:p,roleLogicalId:c,policyLogicalId:u}}static createOutboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,domain:a,configurationSetName:s,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:a,CONFIGURATION_SET:s||""}},Code:{ZipFile:k.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:a,organizedPrefix:s="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:a,ORGANIZED_PREFIX:s}},Code:{ZipFile:k.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"InboundEmail"}]}},y={Type:"AWS::Lambda::Permission",Properties:{FunctionName:R.Ref(m),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:R.Ref("AWS::AccountId")}};return{function:g,permission:y,logicalId:m,permissionLogicalId:p}}static createEmailConversionLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:a,convertedPrefix:s="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:a,CONVERTED_PREFIX:s}},Code:{ZipFile:k.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:a}=e,s=a??["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:s[0],Function:n,Filter:Object.keys(c).length>0?c:void 0}]}}}static createS3LambdaPermission(e){let{slug:n,environment:r,lambdaLogicalId:i,s3BucketArn:a}=e,s=l({slug:n,environment:r,resourceType:"s3-lambda-permission"}),c=o(s);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:R.Ref(i),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:a}},logicalId:c}}static createEmailProcessingStack(e){let{slug:n,environment:r,domain:i,s3BucketName:a,s3BucketArn:s,configurationSetName:c,enableInbound:u=!0,enableConversion:d=!0}=e,m={},{role:p,policy:g,roleLogicalId:y,policyLogicalId:f}=k.createEmailLambdaRole({slug:n,environment:r,s3BucketArn:s,sesIdentityArn:`arn:aws:ses:*:*:identity/${i}`});m[y]=p,m[f]=g;let{function:h,logicalId:S}=k.createOutboundEmailLambda({slug:n,environment:r,roleArn:R.GetAtt(y,"Arn"),domain:i,configurationSetName:c});m[S]=h;let C={roleLogicalId:y,outboundLambdaLogicalId:S};if(u){let{function:P,permission:E,logicalId:v,permissionLogicalId:I}=k.createInboundEmailLambda({slug:n,environment:r,roleArn:R.GetAtt(y,"Arn"),s3BucketName:a});m[v]=P,m[I]=E;let{permission:D,logicalId:N}=k.createS3LambdaPermission({slug:n,environment:r,lambdaLogicalId:v,s3BucketArn:s});m[N]=D,C.inboundLambdaLogicalId=v}if(d){let{function:P,logicalId:E}=k.createEmailConversionLambda({slug:n,environment:r,roleArn:R.GetAtt(y,"Arn"),s3BucketName:a});m[E]=P,C.conversionLambdaLogicalId=E}return{resources:m,outputs:C}}static LambdaCode={outboundEmail:`
|
|
588
|
+
`}class ot{static createFileSystem(e){let{slug:n,environment:r,encrypted:i=!0,kmsKeyId:a,performanceMode:s="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:s,ThroughputMode:c,FileSystemTags:[{Key:"Name",Value:m},{Key:"Environment",Value:r}]}};if(a)g.Properties.KmsKeyId=a;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:a,securityGroups:s,ipAddress:c}=n,u=l({slug:r,environment:i,resourceType:"efs-mt"}),d=o(`${u}-${a}`),m={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:R.Ref(e),SubnetId:a,SecurityGroups:s}};if(c)m.Properties.IpAddress=c;return{mountTarget:m,logicalId:d}}static createAccessPoint(e,n){let{slug:r,environment:i,path:a="/",uid:s="1000",gid:c="1000",permissions:u="755"}=n,d=l({slug:r,environment:i,resourceType:"efs-ap"}),m=o(`${d}-${a.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:R.Ref(e),PosixUser:{Uid:s,Gid:c},RootDirectory:{Path:a,CreationInfo:{OwnerUid:s,OwnerGid:c,Permissions:u}},AccessPointTags:[{Key:"Name",Value:`${d}-${a}`},{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 a=`AFTER_${r}_DAYS`;e.Properties.LifecyclePolicies.push({TransitionToIA:a})}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:a=[],sourceCidrBlocks:s=[],description:c}=e,u=l({slug:n,environment:r,resourceType:"efs-sg"}),d=o(u),m=[];for(let g of a)m.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:g,Description:"NFS from security group"});for(let g of s)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:a,securityGroupId:s}=n,c=[],u=[];for(let d=0;d<a.length;d++){let m=a[d],p=l({slug:r,environment:i,resourceType:"efs-mt"}),g=o(`${p}-az${d+1}`),y={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:R.Ref(e),SubnetId:m,SecurityGroups:[s]}};c.push(y),u.push(g)}return{mountTargets:c,logicalIds:u}}static createCompleteFileSystem(e){let{slug:n,environment:r,vpcId:i,subnetIds:a,sourceSecurityGroupIds:s=[],encrypted:c=!0,performanceMode:u="generalPurpose",throughputMode:d="elastic",enableBackup:m=!0,transitionToIA:p}=e,g={},{fileSystem:y,logicalId:f}=ot.createFileSystem({slug:n,environment:r,encrypted:c,performanceMode:u,throughputMode:d,enableBackup:m});if(p)ot.setLifecyclePolicy(y,{transitionToIA:p,transitionToPrimary:!0});g[f]=y;let{securityGroup:h,logicalId:S}=ot.createEfsSecurityGroup({slug:n,environment:r,vpcId:i,sourceSecurityGroupIds:s});g[S]=h;let{mountTargets:C,logicalIds:P}=ot.createMultiAzMountTargets(f,{slug:n,environment:r,subnetIds:a,securityGroupId:R.Ref(S)});for(let E=0;E<C.length;E++)g[P[E]]=C[E];return{resources:g,outputs:{fileSystemId:f,securityGroupId:S,mountTargetIds:P}}}}class k{static verifyDomain(e){let{domain:n,slug:r,environment:i,enableDkim:a=!0,dkimKeyLength:s="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(a)d.Properties.DkimSigningAttributes={NextSigningKeyLength:s};return{emailIdentity:d,logicalId:u}}static createDkimRecords(e,n,r){let i=[];for(let a=0;a<n.length;a++){let s=n[a],c=o(`dkim-${e.replace(/\./g,"")}-${a+1}`),u={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:r,Name:`${s}._domainkey.${e}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${s}.dkim.amazonses.com`]}};i.push({record:u,logicalId:c})}return i}static createConfigurationSet(e){let{slug:n,environment:r,name:i,reputationMetrics:a=!0,sendingEnabled:s=!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:a},SendingOptions:{SendingEnabled:s},SuppressionOptions:{SuppressedReasons:p}}},logicalId:m}}static createReceiptRuleSet(e){let{slug:n,environment:r,name:i}=e,a=i||l({slug:n,environment:r,resourceType:"ses-ruleset"}),s=o(a);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:a}},logicalId:s}}static createReceiptRule(e,n){let{slug:r,environment:i,ruleSetName:a,recipients:s,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:a,Rule:{Name:y,Enabled:c,ScanEnabled:u,TlsPolicy:d,Recipients:s,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:a=!1}=r||{},s=o(`spf-${e.replace(/\./g,"")}`),c="v=spf1 include:amazonses.com";for(let d of i)c+=` include:${d}`;return c+=a?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n,Name:e,Type:"TXT",TTL:300,ResourceRecords:[`"${c}"`]}},logicalId:s}}static createDmarcRecord(e,n,r){let{policy:i="none",subdomainPolicy:a,percentage:s=100,reportingEmail:c,forensicEmail:u}=r||{},d=o(`dmarc-${e.replace(/\./g,"")}`),m=`v=DMARC1; p=${i}; pct=${s}`;if(a)m+=`; sp=${a}`;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:a,s3KeyPrefix:s="inbound/",region:c,hostedZoneId:u,lambdaFunctionArn:d,snsTopicArn:m}=e,p={},{ruleSet:g,logicalId:y}=k.createReceiptRuleSet({slug:n,environment:r});p[y]=g;let{receiptRule:f,logicalId:h}=k.createReceiptRule(y,{slug:n,environment:r,ruleSetName:g.Properties.RuleSetName||`${n}-${r}-receipt-rule-set`,recipients:[i],s3Action:{bucketName:a,prefix:s},lambdaAction:d?{functionArn:d,invocationType:"Event"}:void 0,snsAction:m?{topicArn:m}:void 0});p[h]=f;let{record:S,logicalId:C}=k.createMxRecord(i,u,c);return p[C]=S,{resources:p,outputs:{ruleSetLogicalId:y,ruleLogicalId:h,mxRecordLogicalId:C}}}static createCompleteDomainSetup(e){let{slug:n,environment:r,domain:i,hostedZoneId:a,region:s,enableInbound:c=!1,inboundS3Bucket:u,dmarcReportingEmail:d}=e,m={},{emailIdentity:p,logicalId:g}=k.verifyDomain({domain:i,slug:n,environment:r});m[g]=p;let{configurationSet:y,logicalId:f}=k.createConfigurationSet({slug:n,environment:r});m[f]=y;let{record:h,logicalId:S}=k.createSpfRecord(i,a);m[S]=h;let{record:C,logicalId:P}=k.createDmarcRecord(i,a,{policy:"none",reportingEmail:d||`dmarc-reports@${i}`});if(m[P]=C,c&&u){let E=k.createInboundEmailSetup({slug:n,environment:r,domain:i,s3BucketName:u,region:s,hostedZoneId:a});Object.assign(m,E.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 k.InboundSmtpEndpoints}static createEmailLambdaRole(e){let{slug:n,environment:r,s3BucketArn:i,sesIdentityArn:a}=e,s=l({slug:n,environment:r,resourceType:"email-lambda-role"}),c=o(s),u=o(`${s}-policy`),d={Type:"AWS::IAM::Role",Properties:{RoleName:s,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},m=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[i,`${i}/*`]}];if(a)m.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:a});let p={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${s}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:m},Roles:[R.Ref(c)]}};return{role:d,policy:p,roleLogicalId:c,policyLogicalId:u}}static createOutboundEmailLambda(e){let{slug:n,environment:r,roleArn:i,domain:a,configurationSetName:s,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:a,CONFIGURATION_SET:s||""}},Code:{ZipFile:k.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:a,organizedPrefix:s="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:a,ORGANIZED_PREFIX:s}},Code:{ZipFile:k.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:d},{Key:"Environment",Value:r},{Key:"Purpose",Value:"InboundEmail"}]}},y={Type:"AWS::Lambda::Permission",Properties:{FunctionName:R.Ref(m),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:R.Ref("AWS::AccountId")}};return{function:g,permission:y,logicalId:m,permissionLogicalId:p}}static createEmailConversionLambda(e){let{slug:n,environment:r,roleArn:i,s3BucketName:a,convertedPrefix:s="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:a,CONVERTED_PREFIX:s}},Code:{ZipFile:k.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:a}=e,s=a??["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:s[0],Function:n,Filter:Object.keys(c).length>0?c:void 0}]}}}static createS3LambdaPermission(e){let{slug:n,environment:r,lambdaLogicalId:i,s3BucketArn:a}=e,s=l({slug:n,environment:r,resourceType:"s3-lambda-permission"}),c=o(s);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:R.Ref(i),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:a}},logicalId:c}}static createEmailProcessingStack(e){let{slug:n,environment:r,domain:i,s3BucketName:a,s3BucketArn:s,configurationSetName:c,enableInbound:u=!0,enableConversion:d=!0}=e,m={},{role:p,policy:g,roleLogicalId:y,policyLogicalId:f}=k.createEmailLambdaRole({slug:n,environment:r,s3BucketArn:s,sesIdentityArn:`arn:aws:ses:*:*:identity/${i}`});m[y]=p,m[f]=g;let{function:h,logicalId:S}=k.createOutboundEmailLambda({slug:n,environment:r,roleArn:R.GetAtt(y,"Arn"),domain:i,configurationSetName:c});m[S]=h;let C={roleLogicalId:y,outboundLambdaLogicalId:S};if(u){let{function:P,permission:E,logicalId:v,permissionLogicalId:I}=k.createInboundEmailLambda({slug:n,environment:r,roleArn:R.GetAtt(y,"Arn"),s3BucketName:a});m[v]=P,m[I]=E;let{permission:D,logicalId:N}=k.createS3LambdaPermission({slug:n,environment:r,lambdaLogicalId:v,s3BucketArn:s});m[N]=D,C.inboundLambdaLogicalId=v}if(d){let{function:P,logicalId:E}=k.createEmailConversionLambda({slug:n,environment:r,roleArn:R.GetAtt(y,"Arn"),s3BucketName:a});m[E]=P,C.conversionLambdaLogicalId=E}return{resources:m,outputs:C}}static LambdaCode={outboundEmail:`
|
|
589
589
|
const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
|
|
590
590
|
const ses = new SESClient({});
|
|
591
591
|
|
|
@@ -2271,14 +2271,14 @@ function resolveTemplate(template, data) {
|
|
|
2271
2271
|
}
|
|
2272
2272
|
return result;
|
|
2273
2273
|
}
|
|
2274
|
-
`;class Re{static LambdaCode={send:ft,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: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"]},a={Ref:`${e.slug}PinpointApp`},s={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:a,messageLogTable:s,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(n,Re.createReceiveLambda({slug:e.slug,roleArn:i,optOutTable:c,messageLogTable:s,notificationTopicArn:u,webhookUrl:e.webhookUrl}));return Object.assign(n,Re.createDeliveryStatusLambda({slug:e.slug,roleArn:i,messageLogTable:s,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 Lr(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 a of[i.uid,i.gid,...i.secondaryGids??[]])if(!Number.isInteger(a)||a<0||a>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${a}`);return{Uid:i.uid,Gid:i.gid,...i.secondaryGids?.length?{SecondaryGids:i.secondaryGids}:{}}}function Or(e,n){return typeof e==="string"?`/${e}/${n}`:{"Fn::Sub":[`/\${FileSystemId}/${n}`,{FileSystemId:e}]}}function $r(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 Ko{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 a=`${ht(e.slug)}${ht(e.environment)}Sftp`,s=`${a}Server`,c={},u;if(e.logging!==!1){let d=`${a}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[s]={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=`${a}${p}User`,f=m.roleArn;if(!f){let h=`${a}${p}Role`,S;if(n.type==="efs")S=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:$r(n.fileSystemId)}];else{let C=`arn:aws:s3:::${n.bucket}`;S=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:C,Condition:{StringLike:{"s3:prefix":[g,`${g}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${C}/${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:[s],Properties:{ServerId:{Ref:s},UserName:d,Role:f,HomeDirectoryType:"PATH",HomeDirectory:n.type==="efs"?Or(n.fileSystemId,g):`/${n.bucket}/${g}`,...n.type==="efs"?{PosixProfile:Lr(d,m,n.posixProfile)}:{},SshPublicKeys:m.sshPublicKeys}}}return{resources:c,serverLogicalId:s,domain:r}}}class He{static createBedrockRole(e,n){let{slug:r,environment:i,name:a,models:s=["*"],allowStreaming:c=!0}=n,u=a||l({slug:r,environment:i,resourceType:"bedrock-role"}),d=o(u),m=["bedrock:InvokeModel"];if(c)m.push("bedrock:InvokeModelWithResponseStream");let p=s.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:a=["*"],allowInvoke:s=!0,allowStreaming:c=!0,allowAsync:u=!1}=e,d=i||l({slug:n,environment:r,resourceType:"bedrock-policy"}),m=o(d),p=[];if(s)p.push("bedrock:InvokeModel");if(c)p.push("bedrock:InvokeModelWithResponseStream");if(u)p.push("bedrock:InvokeModelAsync");let g=a.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 He.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return He.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return He.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,n=["*"],r=!0){let i=["bedrock:InvokeModel"];if(r)i.push("bedrock:InvokeModelWithResponseStream");let a=n.map((s)=>s==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${s}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:i,Resource:a}]}}),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 Wt{static createPostgres(e){return Wt.createRDSInstance("postgres","16.2",e)}static createMysql(e){return Wt.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,n,r){let{slug:i,environment:a,instanceClass:s="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:C=7,publiclyAccessible:P=!1,enableCloudwatchLogs:E=!0,deletionProtection:v=!0}=r,I=l({slug:i,environment:a,resourceType:`${e}-db`}),D=o(I),N,M;if(g&&g.length>0){let O=l({slug:i,environment:a,resourceType:"db-subnet-group"});M=o(O),N={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:O,DBSubnetGroupDescription:`Subnet group for ${I}`,SubnetIds:g,Tags:[{Key:"Name",Value:O},{Key:"Environment",Value:a}]}}}let F={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:I,DBInstanceClass:s,Engine:e,EngineVersion:n,MasterUsername:d,MasterUserPassword:m,AllocatedStorage:c,StorageType:u,StorageEncrypted:f,MultiAZ:S,BackupRetentionPeriod:C,PubliclyAccessible:P,DeletionProtection:v,Tags:[{Key:"Name",Value:I},{Key:"Environment",Value:a}]}};if(p)F.Properties.DBName=p;if(h)F.Properties.KmsKeyId=h;if(M)F.Properties.DBSubnetGroupName=R.Ref(M);if(y&&y.length>0)F.Properties.VPCSecurityGroups=y;if(E)F.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:F,subnetGroup:N,logicalId:D,subnetGroupId:M}}static createReadReplica(e,n){let{slug:r,environment:i,instanceClass:a="db.t3.micro",securityGroupIds:s,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:a,SourceDBInstanceIdentifier:R.Ref(e),PubliclyAccessible:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i},{Key:"Type",Value:"ReadReplica"}]}};if(s&&s.length>0)m.Properties.VPCSecurityGroups=s;return{replica:m,logicalId:d}}static createParameterGroup(e,n,r){let{slug:i,environment:a,parameters:s={}}=r,c=l({slug:i,environment:a,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:s,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:a}]}},logicalId:u}}static enableBackup(e,n=7){return e.Properties.BackupRetentionPeriod=n,e}static createTable(e){let{slug:n,environment:r,tableName:i,partitionKey:a,sortKey:s,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"}),C=o(S),P=[{AttributeName:a.name,AttributeType:a.type}];if(s)P.push({AttributeName:s.name,AttributeType:s.type});let E=[{AttributeName:a.name,KeyType:"HASH"}];if(s)E.push({AttributeName:s.name,KeyType:"RANGE"});let v={Type:"AWS::DynamoDB::Table",Properties:{TableName:S,BillingMode:c,AttributeDefinitions:P,KeySchema:E,Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:r}]}};if(c==="PROVISIONED")v.Properties.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(m)v.Properties.StreamSpecification={StreamViewType:p};if(g)v.Properties.SSESpecification={SSEEnabled:!0,SSEType:y?"KMS":"AES256",KMSMasterKeyId:y};if(f)v.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(h)v.Properties.TimeToLiveSpecification={AttributeName:h,Enabled:!0};return{table:v,logicalId:C}}static addGlobalSecondaryIndex(e,n){let{indexName:r,partitionKey:i,sortKey:a,projectionType:s="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(a&&!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===a.name))e.Properties.AttributeDefinitions.push({AttributeName:a.name,AttributeType:a.type});let m=[{AttributeName:i.name,KeyType:"HASH"}];if(a)m.push({AttributeName:a.name,KeyType:"RANGE"});let p={IndexName:r,KeySchema:m,Projection:{ProjectionType:s,NonKeyAttributes:s==="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 $i{static createRedis(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:a="7.1",port:s=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:C,kmsKeyId:P,snapshotRetentionDays:E=7,snapshotWindow:v,maintenanceWindow:I}=e,D=l({slug:n,environment:r,resourceType:"redis"}),N=o(D),M,F;if(c&&c.length>0){let G=l({slug:n,environment:r,resourceType:"cache-subnet-group"});F=o(G),M={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:G,Description:`Subnet group for ${D}`,SubnetIds:c,Tags:[{Key:"Name",Value:G},{Key:"Environment",Value:r}]}}}let O={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:D,ReplicationGroupDescription:`Redis cluster for ${n} ${r}`,Engine:"redis",EngineVersion:a,CacheNodeType:i,Port:s,AutomaticFailoverEnabled:m,MultiAZEnabled:p,AtRestEncryptionEnabled:h,TransitEncryptionEnabled:S,SnapshotRetentionLimit:E,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(C)O.Properties.AuthToken=C;if(P)O.Properties.KmsKeyId=P;if(F)O.Properties.CacheSubnetGroupName=R.Ref(F);if(u&&u.length>0)O.Properties.SecurityGroupIds=u;if(v)O.Properties.SnapshotWindow=v;if(I)O.Properties.PreferredMaintenanceWindow=I;return{replicationGroup:O,subnetGroup:M,logicalId:N,subnetGroupId:F}}static createMemcached(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:a="1.6.22",port:s=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 P=l({slug:n,environment:r,resourceType:"cache-subnet-group"});S=o(P),h={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:P,Description:`Subnet group for ${y}`,SubnetIds:u,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}}}let C={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:y,CacheNodeType:i,Engine:"memcached",EngineVersion:a,NumCacheNodes:c,Port:s,AZMode:m,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(S)C.Properties.CacheSubnetGroupName=R.Ref(S);if(d&&d.length>0)C.Properties.VpcSecurityGroupIds=d;if(p&&p.length>0)C.Properties.PreferredAvailabilityZones=p;if(g)C.Properties.PreferredMaintenanceWindow=g;return{cluster:C,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:a={}}=n,s=l({slug:r,environment:i,resourceType:"redis-params"}),c=o(s);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${s}`,Properties:a,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:c}}static createMemcachedParameterGroup(e,n){let{slug:r,environment:i,parameters:a={}}=n,s=l({slug:r,environment:i,resourceType:"memcached-params"}),c=o(s);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${s}`,Properties:a,Tags:[{Key:"Name",Value:s},{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:a,managedPolicyArns:s}=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(a&&a.length>0)d.Properties.Groups=a;if(s&&s.length>0)d.Properties.ManagedPolicyArns=s;return{user:d,logicalId:u}}static createRole(e){let{slug:n,environment:r,roleName:i,servicePrincipal:a,awsPrincipal:s,managedPolicyArns:c}=e,u=i||l({slug:n,environment:r,resourceType:"role"}),d=o(u),m={};if(a)m.Service=a;if(s)m.AWS=s;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:a}=e,s=i||l({slug:n,environment:r,resourceType:"group"}),c=o(s),u={Type:"AWS::IAM::Group",Properties:{GroupName:s}};if(a&&a.length>0)u.Properties.ManagedPolicyArns=a;return{group:u,logicalId:c}}static createPolicy(e){let{slug:n,environment:r,policyName:i,description:a,statements:s}=e,c=i||l({slug:n,environment:r,resourceType:"policy"}),u=o(c),d=s.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:a||`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((a)=>({Effect:a.effect||"Allow",Action:a.actions,Resource:a.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((a)=>({Effect:a.effect||"Allow",Action:a.actions,Resource:a.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:a="Active"}=n,s=l({slug:r,environment:i,resourceType:"access-key"}),c=o(s);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:R.Ref(e),Status:a}},logicalId:c}}static createInstanceProfile(e,n){let{slug:r,environment:i,profileName:a}=n,s=a||l({slug:r,environment:i,resourceType:"instance-profile"}),c=o(s);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:s,Roles:[R.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:a=!0}=e,s={},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});s[d]=u;let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cicd-user"}),managedPolicyArns:[R.Ref(d)]});s[p]=m;let g,y;if(a){let f=Ie.createAccessKey(p,{slug:n,environment:r});g=f.accessKey,y=f.logicalId,s[y]=g}return{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:s}}static createCrossAccountRole(e){let{slug:n,environment:r,trustedAccountIds:i,externalId:a,permissions:s,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:s});u[m]=d;let p=l({slug:n,environment:r,resourceType:"cross-account-role"}),g=o(p),y={};if(a)y.StringEquals={"sts:ExternalId":a};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:[R.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,a={},s=[],c=[];switch(i){case"readonly":c=[Ie.ManagedPolicies.ReadOnlyAccess];break;case"deploy":s=[{sid:"S3Deploy",actions:["s3:*"],resources:"*"},{sid:"CloudFrontDeploy",actions:["cloudfront:*"],resources:"*"},{sid:"ECSDeploy",actions:["ecs:*"],resources:"*"},{sid:"ECRDeploy",actions:["ecr:*"],resources:"*"},{sid:"LambdaDeploy",actions:["lambda:*"],resources:"*"},{sid:"CloudFormationDeploy",actions:["cloudformation:*"],resources:"*"},{sid:"IAMPassRole",actions:["iam:PassRole"],resources:"*"}];break;case"admin":c=[Ie.ManagedPolicies.AdministratorAccess];break}let u,d;if(s.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:s});u=f.policy,d=f.logicalId,a[d]=u,c=[R.Ref(d)]}let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cli-user"}),managedPolicyArns:c});a[p]=m;let{accessKey:g,logicalId:y}=Ie.createAccessKey(p,{slug:n,environment:r});return a[y]=g,{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:a}}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 Jo{static createRestApi(e){let{slug:n,environment:r,name:i,description:a,endpointType:s="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:a||`REST API for ${n} ${r}`,EndpointConfiguration:{Types:[s]},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:a,corsEnabled:s=!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:a||`HTTP API for ${n} ${r}`,ProtocolType:"HTTP",Tags:{Name:g,Environment:r}}};if(s)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:a}=e,s=i||l({slug:n,environment:r,resourceType:"ws-api"}),c=o(s);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:s,Description:a||`WebSocket API for ${n} ${r}`,ProtocolType:"WEBSOCKET",Tags:{Name:s,Environment:r}}},logicalId:c}}static createDeployment(e,n){let{slug:r,environment:i,description:a}=n,s=l({slug:r,environment:i,resourceType:"api-deployment"}),c=o(s);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:R.Ref(e),Description:a||`Deployment for ${s}`}},logicalId:c}}static createStage(e,n,r){let{slug:i,environment:a,stageName:s,description:c,cacheEnabled:u=!1,cacheSize:d="0.5",variables:m,throttling:p}=r,g=l({slug:i,environment:a,resourceType:"api-stage"}),y=o(g),f={Type:"AWS::ApiGateway::Stage",Properties:{StageName:s||a,RestApiId:R.Ref(e),DeploymentId:R.Ref(n),Description:c,CacheClusterEnabled:u,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:a}]}};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:a,type:s,functionArn:c,identitySource:u,userPoolArns:d,ttl:m=300}=n,p=a||l({slug:r,environment:i,resourceType:"api-authorizer"}),g=o(p),y={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:p,Type:s,RestApiId:R.Ref(e),AuthorizerResultTtlInSeconds:m}};if(s==="TOKEN"||s==="REQUEST"){if(!c)throw Error("Lambda authorizer requires functionArn");y.Properties.AuthorizerUri=c,y.Properties.IdentitySource=u||"method.request.header.Authorization"}if(s==="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:a=["*"],maxAge:s=86400,allowCredentials:c=!1}=n;return e.Properties.CorsConfiguration={AllowOrigins:r,AllowMethods:i,AllowHeaders:a,MaxAge:s,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 $e{static createTopic(e){let{slug:n,environment:r,topicName:i,displayName:a,encrypted:s=!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:a||u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(s&&c)m.Properties.KmsMasterKeyId=c;return{topic:m,logicalId:d}}static subscribe(e,n){let{slug:r,environment:i,protocol:a,endpoint:s,filterPolicy:c,rawMessageDelivery:u=!1}=n,d=l({slug:r,environment:i,resourceType:"subscription"}),m=s.replace(/[^a-zA-Z0-9]/g,""),p=m.length>12?m.slice(-12):m,g=o(`${d}-${a}-${p}`),y={Type:"AWS::SNS::Subscription",Properties:{TopicArn:R.Ref(e),Protocol:a,Endpoint:s,RawMessageDelivery:u}};if(c)y.Properties.FilterPolicy=c;return{subscription:y,logicalId:g}}static subscribeEmail(e,n,r){return $e.subscribe(e,{...r,protocol:"email",endpoint:n})}static subscribeLambda(e,n,r){return $e.subscribe(e,{...r,protocol:"lambda",endpoint:n,rawMessageDelivery:!0})}static subscribeSqs(e,n,r){return $e.subscribe(e,{...r,protocol:"sqs",endpoint:n})}static subscribeHttp(e,n,r){let i=n.startsWith("https://")?"https":"http";return $e.subscribe(e,{...r,protocol:i,endpoint:n})}static subscribeSms(e,n,r){return $e.subscribe(e,{...r,protocol:"sms",endpoint:n})}static setTopicPolicy(e,n){let{slug:r,environment:i,allowedPrincipals:a,allowedServices:s,actions:c="SNS:Publish"}=n,u=l({slug:r,environment:i,resourceType:"topic-policy"}),d=o(u),m={};if(a)m.AWS=a;if(s)m.Service=s;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[R.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:c,Resource:R.Ref(e)}]}}},logicalId:d}}static allowCloudWatchAlarms(e,n){return $e.setTopicPolicy(e,{...n,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,n){return $e.setTopicPolicy(e,{...n,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,n){return $e.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)=>$e.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>$e.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>$e.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class lu{static createStateMachine(e){let{slug:n,environment:r,stateMachineName:i,type:a="STANDARD",definition:s,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=R.GetAtt(y,"Arn")}let h={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:m,StateMachineType:a,DefinitionString:JSON.stringify(s),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((a,s)=>{let c=s===r.length-1;i[a.name]={...a.state,Next:c?void 0:r[s+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 Li{static createAlarm(e){let{slug:n,environment:r,alarmName:i,metricName:a,namespace:s,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:C,unit:P,datapointsToAlarm:E}=e,v=i||l({slug:n,environment:r,resourceType:"alarm"}),I=o(v),D={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:v,MetricName:a,Namespace:s,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(C)D.Properties.Dimensions=Object.entries(C).map(([N,M])=>({Name:N,Value:M}));if(P)D.Properties.Unit=P;if(E!==void 0)D.Properties.DatapointsToAlarm=E;return{alarm:D,logicalId:I}}static createCompositeAlarm(e){let{slug:n,environment:r,alarmName:i,alarmRule:a,actionsEnabled:s=!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:a,ActionsEnabled:s}};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:a}=e,s=i||l({slug:n,environment:r,resourceType:"dashboard"}),c=o(s),u={widgets:a.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:s,DashboardBody:JSON.stringify(u)}},logicalId:c}}static createLogGroup(e){let{slug:n,environment:r,logGroupName:i,retentionInDays:a,kmsKeyId:s}=e,c=i||l({slug:n,environment:r,resourceType:"log-group"}),u=o(c),d={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:c}};if(a!==void 0)d.Properties.RetentionInDays=a;if(s)d.Properties.KmsKeyId=s;return{logGroup:d,logicalId:u}}static createLogStream(e,n){let{slug:r,environment:i,logStreamName:a}=n,s=a||l({slug:r,environment:i,resourceType:"log-stream"}),c=o(s);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:R.Ref(e),LogStreamName:s}},logicalId:c}}static createMetricFilter(e,n){let{slug:r,environment:i,filterName:a,filterPattern:s,metricTransformations:c}=n,u=a||l({slug:r,environment:i,resourceType:"metric-filter"}),d=o(u);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:R.Ref(e),FilterPattern:s,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,a)=>({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:a?[a]:void 0}),highMemory:(e,n,r,i=80,a)=>({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:a?[a]:void 0}),highDisk:(e,n,r,i=80,a)=>({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:a?[a]:void 0}),lambdaErrors:(e,n,r,i=5,a)=>({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:a?[a]:void 0}),lambdaThrottles:(e,n,r,i=10,a)=>({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:a?[a]:void 0}),apiGateway5xxErrors:(e,n,r,i=10,a)=>({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:a?[a]:void 0}),apiGateway4xxErrors:(e,n,r,i=50,a)=>({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:a?[a]:void 0}),dynamoDBThrottles:(e,n,r,i=5,a)=>({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:a?[a]:void 0}),rdsCpu:(e,n,r,i=80,a)=>({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:a?[a]:void 0}),rdsFreeStorage:(e,n,r,i=5368709120,a)=>({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:a?[a]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,n,r,i=100,a)=>({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:a?[a]:void 0}),albUnhealthyTargets:(e,n,r,i,a=1,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:a,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:r,TargetGroup:i},alarmActions:s?[s]: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,a)=>({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:a?[a]: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,a)=>({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:a?[a]:void 0})};static DashboardWidgets={metric:(e,n,r,i,a,s)=>({type:"metric",x:e,y:n,width:r,height:i,properties:{metrics:a,title:s||"Metrics",region:"us-east-1",period:300}}),text:(e,n,r,i,a)=>({type:"text",x:e,y:n,width:r,height:i,properties:{markdown:a}}),log:(e,n,r,i,a,s)=>({type:"log",x:e,y:n,width:r,height:i,properties:{query:`SOURCE '${a.join("' | SOURCE '")}'
|
|
2274
|
+
`;class Re{static LambdaCode={send:ft,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: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"]},a={Ref:`${e.slug}PinpointApp`},s={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:a,messageLogTable:s,senderId:e.senderId,originationNumber:e.originationNumber})),e.twoWayEnabled)Object.assign(n,Re.createReceiveLambda({slug:e.slug,roleArn:i,optOutTable:c,messageLogTable:s,notificationTopicArn:u,webhookUrl:e.webhookUrl}));return Object.assign(n,Re.createDeliveryStatusLambda({slug:e.slug,roleArn:i,messageLogTable:s,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 a of[i.uid,i.gid,...i.secondaryGids??[]])if(!Number.isInteger(a)||a<0||a>4294967295)throw Error(`sftp: user ${e} has an invalid posixProfile id ${a}`);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 Qo{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 a=`${ht(e.slug)}${ht(e.environment)}Sftp`,s=`${a}Server`,c={},u;if(e.logging!==!1){let d=`${a}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[s]={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=`${a}${p}User`,f=m.roleArn;if(!f){let h=`${a}${p}Role`,S;if(n.type==="efs")S=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Or(n.fileSystemId)}];else{let C=`arn:aws:s3:::${n.bucket}`;S=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:C,Condition:{StringLike:{"s3:prefix":[g,`${g}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${C}/${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:[s],Properties:{ServerId:{Ref:s},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:s,domain:r}}}class He{static createBedrockRole(e,n){let{slug:r,environment:i,name:a,models:s=["*"],allowStreaming:c=!0}=n,u=a||l({slug:r,environment:i,resourceType:"bedrock-role"}),d=o(u),m=["bedrock:InvokeModel"];if(c)m.push("bedrock:InvokeModelWithResponseStream");let p=s.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:a=["*"],allowInvoke:s=!0,allowStreaming:c=!0,allowAsync:u=!1}=e,d=i||l({slug:n,environment:r,resourceType:"bedrock-policy"}),m=o(d),p=[];if(s)p.push("bedrock:InvokeModel");if(c)p.push("bedrock:InvokeModelWithResponseStream");if(u)p.push("bedrock:InvokeModelAsync");let g=a.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 He.createBedrockRole("lambda.amazonaws.com",e)}static enableBedrockForEcs(e){return He.createBedrockRole("ecs-tasks.amazonaws.com",e)}static enableBedrockForEc2(e){return He.createBedrockRole("ec2.amazonaws.com",e)}static addBedrockPermissions(e,n=["*"],r=!0){let i=["bedrock:InvokeModel"];if(r)i.push("bedrock:InvokeModelWithResponseStream");let a=n.map((s)=>s==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${s}`);if(!e.Properties.Policies)e.Properties.Policies=[];return e.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:i,Resource:a}]}}),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 Wt{static createPostgres(e){return Wt.createRDSInstance("postgres","16.2",e)}static createMysql(e){return Wt.createRDSInstance("mysql","8.0.35",e)}static createRDSInstance(e,n,r){let{slug:i,environment:a,instanceClass:s="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:C=7,publiclyAccessible:P=!1,enableCloudwatchLogs:E=!0,deletionProtection:v=!0}=r,I=l({slug:i,environment:a,resourceType:`${e}-db`}),D=o(I),N,M;if(g&&g.length>0){let O=l({slug:i,environment:a,resourceType:"db-subnet-group"});M=o(O),N={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:O,DBSubnetGroupDescription:`Subnet group for ${I}`,SubnetIds:g,Tags:[{Key:"Name",Value:O},{Key:"Environment",Value:a}]}}}let F={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:I,DBInstanceClass:s,Engine:e,EngineVersion:n,MasterUsername:d,MasterUserPassword:m,AllocatedStorage:c,StorageType:u,StorageEncrypted:f,MultiAZ:S,BackupRetentionPeriod:C,PubliclyAccessible:P,DeletionProtection:v,Tags:[{Key:"Name",Value:I},{Key:"Environment",Value:a}]}};if(p)F.Properties.DBName=p;if(h)F.Properties.KmsKeyId=h;if(M)F.Properties.DBSubnetGroupName=R.Ref(M);if(y&&y.length>0)F.Properties.VPCSecurityGroups=y;if(E)F.Properties.EnableCloudwatchLogsExports=e==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:F,subnetGroup:N,logicalId:D,subnetGroupId:M}}static createReadReplica(e,n){let{slug:r,environment:i,instanceClass:a="db.t3.micro",securityGroupIds:s,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:a,SourceDBInstanceIdentifier:R.Ref(e),PubliclyAccessible:c,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:i},{Key:"Type",Value:"ReadReplica"}]}};if(s&&s.length>0)m.Properties.VPCSecurityGroups=s;return{replica:m,logicalId:d}}static createParameterGroup(e,n,r){let{slug:i,environment:a,parameters:s={}}=r,c=l({slug:i,environment:a,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:s,Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:a}]}},logicalId:u}}static enableBackup(e,n=7){return e.Properties.BackupRetentionPeriod=n,e}static createTable(e){let{slug:n,environment:r,tableName:i,partitionKey:a,sortKey:s,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"}),C=o(S),P=[{AttributeName:a.name,AttributeType:a.type}];if(s)P.push({AttributeName:s.name,AttributeType:s.type});let E=[{AttributeName:a.name,KeyType:"HASH"}];if(s)E.push({AttributeName:s.name,KeyType:"RANGE"});let v={Type:"AWS::DynamoDB::Table",Properties:{TableName:S,BillingMode:c,AttributeDefinitions:P,KeySchema:E,Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:r}]}};if(c==="PROVISIONED")v.Properties.ProvisionedThroughput={ReadCapacityUnits:u,WriteCapacityUnits:d};if(m)v.Properties.StreamSpecification={StreamViewType:p};if(g)v.Properties.SSESpecification={SSEEnabled:!0,SSEType:y?"KMS":"AES256",KMSMasterKeyId:y};if(f)v.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(h)v.Properties.TimeToLiveSpecification={AttributeName:h,Enabled:!0};return{table:v,logicalId:C}}static addGlobalSecondaryIndex(e,n){let{indexName:r,partitionKey:i,sortKey:a,projectionType:s="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(a&&!e.Properties.AttributeDefinitions.some((g)=>g.AttributeName===a.name))e.Properties.AttributeDefinitions.push({AttributeName:a.name,AttributeType:a.type});let m=[{AttributeName:i.name,KeyType:"HASH"}];if(a)m.push({AttributeName:a.name,KeyType:"RANGE"});let p={IndexName:r,KeySchema:m,Projection:{ProjectionType:s,NonKeyAttributes:s==="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 Ui{static createRedis(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:a="7.1",port:s=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:C,kmsKeyId:P,snapshotRetentionDays:E=7,snapshotWindow:v,maintenanceWindow:I}=e,D=l({slug:n,environment:r,resourceType:"redis"}),N=o(D),M,F;if(c&&c.length>0){let G=l({slug:n,environment:r,resourceType:"cache-subnet-group"});F=o(G),M={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:G,Description:`Subnet group for ${D}`,SubnetIds:c,Tags:[{Key:"Name",Value:G},{Key:"Environment",Value:r}]}}}let O={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:D,ReplicationGroupDescription:`Redis cluster for ${n} ${r}`,Engine:"redis",EngineVersion:a,CacheNodeType:i,Port:s,AutomaticFailoverEnabled:m,MultiAZEnabled:p,AtRestEncryptionEnabled:h,TransitEncryptionEnabled:S,SnapshotRetentionLimit:E,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(C)O.Properties.AuthToken=C;if(P)O.Properties.KmsKeyId=P;if(F)O.Properties.CacheSubnetGroupName=R.Ref(F);if(u&&u.length>0)O.Properties.SecurityGroupIds=u;if(v)O.Properties.SnapshotWindow=v;if(I)O.Properties.PreferredMaintenanceWindow=I;return{replicationGroup:O,subnetGroup:M,logicalId:N,subnetGroupId:F}}static createMemcached(e){let{slug:n,environment:r,nodeType:i="cache.t3.micro",engineVersion:a="1.6.22",port:s=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 P=l({slug:n,environment:r,resourceType:"cache-subnet-group"});S=o(P),h={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:P,Description:`Subnet group for ${y}`,SubnetIds:u,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:r}]}}}let C={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:y,CacheNodeType:i,Engine:"memcached",EngineVersion:a,NumCacheNodes:c,Port:s,AZMode:m,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:r}]}};if(S)C.Properties.CacheSubnetGroupName=R.Ref(S);if(d&&d.length>0)C.Properties.VpcSecurityGroupIds=d;if(p&&p.length>0)C.Properties.PreferredAvailabilityZones=p;if(g)C.Properties.PreferredMaintenanceWindow=g;return{cluster:C,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:a={}}=n,s=l({slug:r,environment:i,resourceType:"redis-params"}),c=o(s);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${e.split(".")[0]}.x`,Description:`Parameter group for ${s}`,Properties:a,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:c}}static createMemcachedParameterGroup(e,n){let{slug:r,environment:i,parameters:a={}}=n,s=l({slug:r,environment:i,resourceType:"memcached-params"}),c=o(s);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${e.split(".")[0]}.${e.split(".")[1]}`,Description:`Parameter group for ${s}`,Properties:a,Tags:[{Key:"Name",Value:s},{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:a,managedPolicyArns:s}=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(a&&a.length>0)d.Properties.Groups=a;if(s&&s.length>0)d.Properties.ManagedPolicyArns=s;return{user:d,logicalId:u}}static createRole(e){let{slug:n,environment:r,roleName:i,servicePrincipal:a,awsPrincipal:s,managedPolicyArns:c}=e,u=i||l({slug:n,environment:r,resourceType:"role"}),d=o(u),m={};if(a)m.Service=a;if(s)m.AWS=s;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:a}=e,s=i||l({slug:n,environment:r,resourceType:"group"}),c=o(s),u={Type:"AWS::IAM::Group",Properties:{GroupName:s}};if(a&&a.length>0)u.Properties.ManagedPolicyArns=a;return{group:u,logicalId:c}}static createPolicy(e){let{slug:n,environment:r,policyName:i,description:a,statements:s}=e,c=i||l({slug:n,environment:r,resourceType:"policy"}),u=o(c),d=s.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:a||`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((a)=>({Effect:a.effect||"Allow",Action:a.actions,Resource:a.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((a)=>({Effect:a.effect||"Allow",Action:a.actions,Resource:a.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:a="Active"}=n,s=l({slug:r,environment:i,resourceType:"access-key"}),c=o(s);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:R.Ref(e),Status:a}},logicalId:c}}static createInstanceProfile(e,n){let{slug:r,environment:i,profileName:a}=n,s=a||l({slug:r,environment:i,resourceType:"instance-profile"}),c=o(s);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:s,Roles:[R.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:a=!0}=e,s={},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});s[d]=u;let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cicd-user"}),managedPolicyArns:[R.Ref(d)]});s[p]=m;let g,y;if(a){let f=Ie.createAccessKey(p,{slug:n,environment:r});g=f.accessKey,y=f.logicalId,s[y]=g}return{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:s}}static createCrossAccountRole(e){let{slug:n,environment:r,trustedAccountIds:i,externalId:a,permissions:s,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:s});u[m]=d;let p=l({slug:n,environment:r,resourceType:"cross-account-role"}),g=o(p),y={};if(a)y.StringEquals={"sts:ExternalId":a};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:[R.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,a={},s=[],c=[];switch(i){case"readonly":c=[Ie.ManagedPolicies.ReadOnlyAccess];break;case"deploy":s=[{sid:"S3Deploy",actions:["s3:*"],resources:"*"},{sid:"CloudFrontDeploy",actions:["cloudfront:*"],resources:"*"},{sid:"ECSDeploy",actions:["ecs:*"],resources:"*"},{sid:"ECRDeploy",actions:["ecr:*"],resources:"*"},{sid:"LambdaDeploy",actions:["lambda:*"],resources:"*"},{sid:"CloudFormationDeploy",actions:["cloudformation:*"],resources:"*"},{sid:"IAMPassRole",actions:["iam:PassRole"],resources:"*"}];break;case"admin":c=[Ie.ManagedPolicies.AdministratorAccess];break}let u,d;if(s.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:s});u=f.policy,d=f.logicalId,a[d]=u,c=[R.Ref(d)]}let{user:m,logicalId:p}=Ie.createUser({slug:n,environment:r,userName:l({slug:n,environment:r,resourceType:"cli-user"}),managedPolicyArns:c});a[p]=m;let{accessKey:g,logicalId:y}=Ie.createAccessKey(p,{slug:n,environment:r});return a[y]=g,{user:m,accessKey:g,policy:u,userLogicalId:p,accessKeyLogicalId:y,policyLogicalId:d,resources:a}}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 Yo{static createRestApi(e){let{slug:n,environment:r,name:i,description:a,endpointType:s="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:a||`REST API for ${n} ${r}`,EndpointConfiguration:{Types:[s]},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:a,corsEnabled:s=!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:a||`HTTP API for ${n} ${r}`,ProtocolType:"HTTP",Tags:{Name:g,Environment:r}}};if(s)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:a}=e,s=i||l({slug:n,environment:r,resourceType:"ws-api"}),c=o(s);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:s,Description:a||`WebSocket API for ${n} ${r}`,ProtocolType:"WEBSOCKET",Tags:{Name:s,Environment:r}}},logicalId:c}}static createDeployment(e,n){let{slug:r,environment:i,description:a}=n,s=l({slug:r,environment:i,resourceType:"api-deployment"}),c=o(s);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:R.Ref(e),Description:a||`Deployment for ${s}`}},logicalId:c}}static createStage(e,n,r){let{slug:i,environment:a,stageName:s,description:c,cacheEnabled:u=!1,cacheSize:d="0.5",variables:m,throttling:p}=r,g=l({slug:i,environment:a,resourceType:"api-stage"}),y=o(g),f={Type:"AWS::ApiGateway::Stage",Properties:{StageName:s||a,RestApiId:R.Ref(e),DeploymentId:R.Ref(n),Description:c,CacheClusterEnabled:u,Tags:[{Key:"Name",Value:g},{Key:"Environment",Value:a}]}};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:a,type:s,functionArn:c,identitySource:u,userPoolArns:d,ttl:m=300}=n,p=a||l({slug:r,environment:i,resourceType:"api-authorizer"}),g=o(p),y={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:p,Type:s,RestApiId:R.Ref(e),AuthorizerResultTtlInSeconds:m}};if(s==="TOKEN"||s==="REQUEST"){if(!c)throw Error("Lambda authorizer requires functionArn");y.Properties.AuthorizerUri=c,y.Properties.IdentitySource=u||"method.request.header.Authorization"}if(s==="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:a=["*"],maxAge:s=86400,allowCredentials:c=!1}=n;return e.Properties.CorsConfiguration={AllowOrigins:r,AllowMethods:i,AllowHeaders:a,MaxAge:s,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 $e{static createTopic(e){let{slug:n,environment:r,topicName:i,displayName:a,encrypted:s=!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:a||u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:r}]}};if(s&&c)m.Properties.KmsMasterKeyId=c;return{topic:m,logicalId:d}}static subscribe(e,n){let{slug:r,environment:i,protocol:a,endpoint:s,filterPolicy:c,rawMessageDelivery:u=!1}=n,d=l({slug:r,environment:i,resourceType:"subscription"}),m=s.replace(/[^a-zA-Z0-9]/g,""),p=m.length>12?m.slice(-12):m,g=o(`${d}-${a}-${p}`),y={Type:"AWS::SNS::Subscription",Properties:{TopicArn:R.Ref(e),Protocol:a,Endpoint:s,RawMessageDelivery:u}};if(c)y.Properties.FilterPolicy=c;return{subscription:y,logicalId:g}}static subscribeEmail(e,n,r){return $e.subscribe(e,{...r,protocol:"email",endpoint:n})}static subscribeLambda(e,n,r){return $e.subscribe(e,{...r,protocol:"lambda",endpoint:n,rawMessageDelivery:!0})}static subscribeSqs(e,n,r){return $e.subscribe(e,{...r,protocol:"sqs",endpoint:n})}static subscribeHttp(e,n,r){let i=n.startsWith("https://")?"https":"http";return $e.subscribe(e,{...r,protocol:i,endpoint:n})}static subscribeSms(e,n,r){return $e.subscribe(e,{...r,protocol:"sms",endpoint:n})}static setTopicPolicy(e,n){let{slug:r,environment:i,allowedPrincipals:a,allowedServices:s,actions:c="SNS:Publish"}=n,u=l({slug:r,environment:i,resourceType:"topic-policy"}),d=o(u),m={};if(a)m.AWS=a;if(s)m.Service=s;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[R.Ref(e)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:m,Action:c,Resource:R.Ref(e)}]}}},logicalId:d}}static allowCloudWatchAlarms(e,n){return $e.setTopicPolicy(e,{...n,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(e,n){return $e.setTopicPolicy(e,{...n,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(e,n){return $e.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)=>$e.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-alerts`,displayName:e.displayName||"Alert Notifications"}),createEventFanout:(e)=>$e.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-events`,displayName:e.displayName||"Event Fanout"}),createNotificationTopic:(e)=>$e.createTopic({...e,topicName:e.topicName||`${e.slug}-${e.environment}-notifications`,displayName:e.displayName||"User Notifications"})}}class lu{static createStateMachine(e){let{slug:n,environment:r,stateMachineName:i,type:a="STANDARD",definition:s,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=R.GetAtt(y,"Arn")}let h={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:m,StateMachineType:a,DefinitionString:JSON.stringify(s),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((a,s)=>{let c=s===r.length-1;i[a.name]={...a.state,Next:c?void 0:r[s+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 Fi{static createAlarm(e){let{slug:n,environment:r,alarmName:i,metricName:a,namespace:s,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:C,unit:P,datapointsToAlarm:E}=e,v=i||l({slug:n,environment:r,resourceType:"alarm"}),I=o(v),D={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:v,MetricName:a,Namespace:s,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(C)D.Properties.Dimensions=Object.entries(C).map(([N,M])=>({Name:N,Value:M}));if(P)D.Properties.Unit=P;if(E!==void 0)D.Properties.DatapointsToAlarm=E;return{alarm:D,logicalId:I}}static createCompositeAlarm(e){let{slug:n,environment:r,alarmName:i,alarmRule:a,actionsEnabled:s=!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:a,ActionsEnabled:s}};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:a}=e,s=i||l({slug:n,environment:r,resourceType:"dashboard"}),c=o(s),u={widgets:a.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:s,DashboardBody:JSON.stringify(u)}},logicalId:c}}static createLogGroup(e){let{slug:n,environment:r,logGroupName:i,retentionInDays:a,kmsKeyId:s}=e,c=i||l({slug:n,environment:r,resourceType:"log-group"}),u=o(c),d={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:c}};if(a!==void 0)d.Properties.RetentionInDays=a;if(s)d.Properties.KmsKeyId=s;return{logGroup:d,logicalId:u}}static createLogStream(e,n){let{slug:r,environment:i,logStreamName:a}=n,s=a||l({slug:r,environment:i,resourceType:"log-stream"}),c=o(s);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:R.Ref(e),LogStreamName:s}},logicalId:c}}static createMetricFilter(e,n){let{slug:r,environment:i,filterName:a,filterPattern:s,metricTransformations:c}=n,u=a||l({slug:r,environment:i,resourceType:"metric-filter"}),d=o(u);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:R.Ref(e),FilterPattern:s,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,a)=>({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:a?[a]:void 0}),highMemory:(e,n,r,i=80,a)=>({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:a?[a]:void 0}),highDisk:(e,n,r,i=80,a)=>({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:a?[a]:void 0}),lambdaErrors:(e,n,r,i=5,a)=>({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:a?[a]:void 0}),lambdaThrottles:(e,n,r,i=10,a)=>({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:a?[a]:void 0}),apiGateway5xxErrors:(e,n,r,i=10,a)=>({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:a?[a]:void 0}),apiGateway4xxErrors:(e,n,r,i=50,a)=>({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:a?[a]:void 0}),dynamoDBThrottles:(e,n,r,i=5,a)=>({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:a?[a]:void 0}),rdsCpu:(e,n,r,i=80,a)=>({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:a?[a]:void 0}),rdsFreeStorage:(e,n,r,i=5368709120,a)=>({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:a?[a]:void 0,unit:"Bytes"}),sqsQueueDepth:(e,n,r,i=100,a)=>({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:a?[a]:void 0}),albUnhealthyTargets:(e,n,r,i,a=1,s)=>({slug:e,environment:n,alarmName:`${e}-${n}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:a,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:r,TargetGroup:i},alarmActions:s?[s]: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,a)=>({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:a?[a]: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,a)=>({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:a?[a]:void 0})};static DashboardWidgets={metric:(e,n,r,i,a,s)=>({type:"metric",x:e,y:n,width:r,height:i,properties:{metrics:a,title:s||"Metrics",region:"us-east-1",period:300}}),text:(e,n,r,i,a)=>({type:"text",x:e,y:n,width:r,height:i,properties:{markdown:a}}),log:(e,n,r,i,a,s)=>({type:"log",x:e,y:n,width:r,height:i,properties:{query:`SOURCE '${a.join("' | SOURCE '")}'
|
|
2275
2275
|
| fields @timestamp, @message
|
|
2276
2276
|
| sort @timestamp desc
|
|
2277
2277
|
| limit 20`,region:"us-east-1",title:s||"Logs"}})};static RetentionPeriods={ONE_DAY:1,THREE_DAYS:3,FIVE_DAYS:5,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,TWO_MONTHS:60,THREE_MONTHS:90,FOUR_MONTHS:120,FIVE_MONTHS:150,SIX_MONTHS:180,ONE_YEAR:365,THIRTEEN_MONTHS:400,EIGHTEEN_MONTHS:545,TWO_YEARS:731,FIVE_YEARS:1827,TEN_YEARS:3653,NEVER_EXPIRE:void 0};static FilterPatterns={errors:"[time, request_id, event_type = ERROR*, ...]",all:"",jsonField:(e,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:a={}}=e,s=[],c=0;if(s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:`# ${n.toUpperCase()} Dashboard (${r})`}}),c+=1,a.ec2InstanceIds&&a.ec2InstanceIds.length>0)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## EC2 Instances"}}),c+=1,s.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:i,metrics:a.ec2InstanceIds.map((u)=>["AWS/EC2","CPUUtilization","InstanceId",u]),period:300,stat:"Average"}}),s.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Network Traffic",region:i,metrics:[...a.ec2InstanceIds.flatMap((u)=>[["AWS/EC2","NetworkIn","InstanceId",u,{label:`${u} In`}],["AWS/EC2","NetworkOut","InstanceId",u,{label:`${u} Out`}]])],period:300,stat:"Sum"}}),s.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Status Checks",region:i,metrics:a.ec2InstanceIds.map((u)=>["AWS/EC2","StatusCheckFailed","InstanceId",u]),period:60,stat:"Maximum"}}),c+=6;if(a.lambdaFunctionNames&&a.lambdaFunctionNames.length>0)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Lambda Functions"}}),c+=1,s.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"Invocations",region:i,metrics:a.lambdaFunctionNames.map((u)=>["AWS/Lambda","Invocations","FunctionName",u]),period:300,stat:"Sum"}}),s.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Duration",region:i,metrics:a.lambdaFunctionNames.map((u)=>["AWS/Lambda","Duration","FunctionName",u]),period:300,stat:"Average"}}),s.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Errors",region:i,metrics:a.lambdaFunctionNames.map((u)=>["AWS/Lambda","Errors","FunctionName",u]),period:300,stat:"Sum"}}),c+=6;if(a.ecsClusterName&&a.ecsServiceName)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## ECS Service"}}),c+=1,s.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:i,metrics:[["AWS/ECS","CPUUtilization","ClusterName",a.ecsClusterName,"ServiceName",a.ecsServiceName]],period:300,stat:"Average"}}),s.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Memory Utilization",region:i,metrics:[["AWS/ECS","MemoryUtilization","ClusterName",a.ecsClusterName,"ServiceName",a.ecsServiceName]],period:300,stat:"Average"}}),s.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Running Tasks",region:i,metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",a.ecsClusterName,"ServiceName",a.ecsServiceName]],period:60,stat:"Average"}}),c+=6;if(a.albName)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Application Load Balancer"}}),c+=1,s.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"Request Count",region:i,metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",a.albName]],period:60,stat:"Sum"}}),s.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Response Time",region:i,metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",a.albName]],period:60,stat:"Average"}}),s.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",a.albName,{label:"4XX"}],["AWS/ApplicationELB","HTTPCode_Target_5XX_Count","LoadBalancer",a.albName,{label:"5XX"}]],period:60,stat:"Sum"}}),c+=6;if(a.rdsInstanceId)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## RDS Database"}}),c+=1,s.push({type:"metric",x:0,y:c,width:8,height:6,properties:{title:"CPU Utilization",region:i,metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",a.rdsInstanceId]],period:300,stat:"Average"}}),s.push({type:"metric",x:8,y:c,width:8,height:6,properties:{title:"Database Connections",region:i,metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",a.rdsInstanceId]],period:60,stat:"Sum"}}),s.push({type:"metric",x:16,y:c,width:8,height:6,properties:{title:"Free Storage Space",region:i,metrics:[["AWS/RDS","FreeStorageSpace","DBInstanceIdentifier",a.rdsInstanceId]],period:300,stat:"Average"}}),c+=6;if(a.sqsQueueNames&&a.sqsQueueNames.length>0)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## SQS Queues"}}),c+=1,s.push({type:"metric",x:0,y:c,width:12,height:6,properties:{title:"Messages Visible",region:i,metrics:a.sqsQueueNames.map((u)=>["AWS/SQS","ApproximateNumberOfMessagesVisible","QueueName",u]),period:60,stat:"Sum"}}),s.push({type:"metric",x:12,y:c,width:12,height:6,properties:{title:"Message Age",region:i,metrics:a.sqsQueueNames.map((u)=>["AWS/SQS","ApproximateAgeOfOldestMessage","QueueName",u]),period:60,stat:"Maximum"}}),c+=6;if(a.logGroupNames&&a.logGroupNames.length>0)s.push({type:"text",x:0,y:c,width:24,height:1,properties:{markdown:"## Application Logs"}}),c+=1,s.push({type:"log",x:0,y:c,width:24,height:6,properties:{query:`SOURCE '${a.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 Li.createDashboard({slug:n,environment:r,widgets:s})}static DashboardTemplates={staticWebsite:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Static Website Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"CloudFront Requests",region:"us-east-1",metrics:[["AWS/CloudFront","Requests","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"Error Rate",region:"us-east-1",metrics:[["AWS/CloudFront","4xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"5XX"}]],period:300,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Bytes Downloaded",region:"us-east-1",metrics:[["AWS/CloudFront","BytesDownloaded","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:e.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",e.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:e.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",e.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",e.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",e.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",e.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",e.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...e.lambdaFunctionNames.map((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:a="GreaterThanThreshold",evaluationPeriods:s=1,period:c=300,statistic:u="Average",treatMissingData:d="missing"}=e;return{MetricName:n,Namespace:r,Threshold:i,ComparisonOperator:a,EvaluationPeriods:s,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:a,autoVerifiedAttributes:s,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(a&&a.length>0)S.Properties.UsernameAttributes=a;if(s&&s.length>0)S.Properties.AutoVerifiedAttributes=s;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:a,generateSecret:s=!1,refreshTokenValidity:c,accessTokenValidity:u,idTokenValidity:d,tokenValidityUnits:m,readAttributes:p,writeAttributes:g,explicitAuthFlows:y,preventUserExistenceErrors:f,enableTokenRevocation:h,callbackURLs:S,logoutURLs:C,allowedOAuthFlows:P,allowedOAuthScopes:E,allowedOAuthFlowsUserPoolClient:v,supportedIdentityProviders:I}=n,D=a||l({slug:r,environment:i,resourceType:"user-pool-client"}),N=o(D);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:D,UserPoolId:R.Ref(e),GenerateSecret:s,RefreshTokenValidity:c,AccessTokenValidity:u,IdTokenValidity:d,TokenValidityUnits:m,ReadAttributes:p,WriteAttributes:g,ExplicitAuthFlows:y,PreventUserExistenceErrors:f,EnableTokenRevocation:h,CallbackURLs:S,LogoutURLs:C,AllowedOAuthFlows:P,AllowedOAuthScopes:E,AllowedOAuthFlowsUserPoolClient:v,SupportedIdentityProviders:I}},logicalId:N}}static createUserPoolDomain(e,n){let{slug:r,environment:i,domain:a,customDomainConfig:s}=n,c=l({slug:r,environment:i,resourceType:"user-pool-domain"}),u=o(c);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:a,UserPoolId:R.Ref(e),CustomDomainConfig:s}},logicalId:u}}static createIdentityPool(e){let{slug:n,environment:r,identityPoolName:i,allowUnauthenticatedIdentities:a=!1,cognitoIdentityProviders:s,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:a,CognitoIdentityProviders:s,SupportedLoginProviders:c,SamlProviderARNs:u,OpenIdConnectProviderARNs:d}},logicalId:p}}static createIdentityPoolRoleAttachment(e,n){let{slug:r,environment:i,authenticatedRole:a,unauthenticatedRole:s,roleMappings:c}=n,u=l({slug:r,environment:i,resourceType:"identity-pool-role-attachment"}),d=o(u),m={authenticated:a};if(s)m.unauthenticated=s;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:R.Ref(e),Roles:m,RoleMappings:c}},logicalId:d}}static createAuthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,a=l({slug:n,environment:r,resourceType:"cognito-authenticated-role"}),s=o(a);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":R.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:a},{Key:"Environment",Value:r}]}},logicalId:s}}static createUnauthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,a=l({slug:n,environment:r,resourceType:"cognito-unauthenticated-role"}),s=o(a);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":R.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:a},{Key:"Environment",Value:r}]}},logicalId:s}}static PasswordPolicies={relaxed:()=>({minimumLength:8,requireLowercase:!1,requireUppercase:!1,requireNumbers:!1,requireSymbols:!1,temporaryPasswordValidityDays:7}),standard:()=>({minimumLength:8,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!1,temporaryPasswordValidityDays:3}),strict:()=>({minimumLength:12,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!0,temporaryPasswordValidityDays:1})};static AuthFlows={standard:["ALLOW_USER_SRP_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],admin:["ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],custom:["ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],all:["ALLOW_USER_SRP_AUTH","ALLOW_USER_PASSWORD_AUTH","ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"]};static OAuthScopes={basic:["openid","email","profile"],all:["openid","email","profile","phone","aws.cognito.signin.user.admin"]};static UseCases={webApp:(e,n,r)=>{let{userPool:i,logicalId:a}=Pe.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Pe.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:s,logicalId:c}=Pe.createUserPoolClient(a,{slug:e,environment:n,explicitAuthFlows:[...Pe.AuthFlows.standard],callbackURLs:[r],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Pe.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:i,poolId:a,client:s,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:a,logicalId:s}=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:R.Ref(s),ProviderName:R.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:R.GetAtt(m,"Arn")});return{userPool:r,poolId:i,client:a,clientId:s,identityPool:c,identityPoolId:u,authRole:d,authRoleId:m,attachment:p,attachmentId:g}}}}import{createHash as Gr}from"node:crypto";import{copyFileSync as _r,existsSync as bt,readdirSync as Wr,readFileSync as Xe,statSync as Hr,writeFileSync as et}from"node:fs";import{basename as Kr,dirname as mn,extname as pn,join as We}from"node:path";class De{static createApplication(e){let{slug:n,environment:r,applicationName:i,computePlatform:a}=e,s=i||l({slug:n,environment:r,resourceType:"deploy-app"}),c=o(s);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:s,ComputePlatform:a,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},logicalId:c}}static createDeploymentGroup(e,n){let{slug:r,environment:i,deploymentGroupName:a,serviceRoleArn:s,autoScalingGroups:c,ec2TagFilters:u,deploymentConfigName:d,autoRollbackConfiguration:m,alarmConfiguration:p,loadBalancerInfo:g,blueGreenDeploymentConfiguration:y}=n,f=a||l({slug:r,environment:i,resourceType:"deploy-group"}),h=o(f);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:R.Ref(e),DeploymentGroupName:f,ServiceRoleArn:s,AutoScalingGroups:c,Ec2TagFilters:u?.map((C)=>({Key:C.key,Value:C.value,Type:C.type})),DeploymentConfigName:d,AutoRollbackConfiguration:m?{Enabled:m.enabled,Events:m.events}:void 0,AlarmConfiguration:p?{Enabled:p.enabled,Alarms:p.alarms?.map((C)=>({Name:C.name})),IgnorePollAlarmFailure:p.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:g?{TargetGroupInfoList:g.targetGroupInfoList?.map((C)=>({Name:C.name})),ElbInfoList:g.elbInfoList?.map((C)=>({Name:C.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:a,trafficRoutingConfig:s}=e,c=i||l({slug:n,environment:r,resourceType:"deploy-config"}),u=o(c);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:c,MinimumHealthyHosts:a?{Type:a.type,Value:a.value}:void 0,TrafficRoutingConfig:s?{Type:s.type,TimeBasedCanary:s.timeBasedCanary?{CanaryPercentage:s.timeBasedCanary.canaryPercentage,CanaryInterval:s.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:s.timeBasedLinear?{LinearPercentage:s.timeBasedLinear.linearPercentage,LinearInterval:s.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId: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:a,logicalId:s}=De.createApplication({slug:e,environment:n,computePlatform:"Server"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(s,{slug:e,environment:n,serviceRoleArn:r,autoScalingGroups:i,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:a,appId:s,deploymentGroup:c,groupId:u}},lambdaCanaryDeployment:(e,n,r,i=10,a=5)=>{let{application:s,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,a)}),{deploymentGroup:m,logicalId:p}=De.createDeploymentGroup(c,{slug:e,environment:n,serviceRoleArn:r,deploymentConfigName:R.Ref(d),autoRollbackConfiguration:De.RollbackConfigs.onAlarmOrFailure()});return{application:s,appId:c,deploymentConfig:u,configId:d,deploymentGroup:m,groupId:p}},ecsBlueGreenDeployment:(e,n,r,i)=>{let{application:a,logicalId:s}=De.createApplication({slug:e,environment:n,computePlatform:"ECS"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(s,{slug:e,environment:n,serviceRoleArn:r,loadBalancerInfo:{targetGroupInfoList:[{name:i}]},blueGreenDeploymentConfiguration:De.BlueGreenConfigs.standard(),autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:a,appId:s,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 ie{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 Gr(n).update(r).digest("hex")}static computeShortHash(e){return ie.computeFileHash(e).slice(0,8)}static getContentType(e){let n=pn(e).toLowerCase();return ie.ContentTypes[n]||"application/octet-stream"}static shouldHashFile(e,n){return![...ie.NoHashPatterns,...n||[]].some((i)=>i.test(e))}static generateHashedFilename(e,n){let r=pn(e),i=Kr(e,r),a=mn(e);if(a===".")return`${i}.${n}${r}`;return We(a,`${i}.${n}${r}`)}static collectFiles(e,n){let r=[],i=n||e;if(!bt(e))return r;let a=Wr(e,{withFileTypes:!0});for(let s of a){let c=We(e,s.name);if(s.isDirectory())r.push(...ie.collectFiles(c,i));else if(s.isFile())r.push(c)}return r}static hashDirectory(e){let{sourceDir:n,outputDir:r,excludePatterns:i=[],hashAlgorithm:a="md5",copyUnhashed:s=!0}=e,c=ie.collectFiles(n),u=[],d={};for(let p of c){let g=p.replace(n,"").replace(/^[/\\]/,""),y=ie.shouldHashFile(g,i),f=Hr(p),h=y?ie.computeFileHash(p,a).slice(0,8):"",S=y?ie.generateHashedFilename(g,h):g,C={originalPath:g,hashedPath:S,hash:h,size:f.size,contentType:ie.getContentType(p)};if(u.push(C),d[g]=S,r){let P=We(r,S),E=mn(P);if(!bt(E)){let{mkdirSync:v}=Vr("node:fs");v(E,{recursive:!0})}if(y||s)_r(p,P)}}let m={version:"1.0",timestamp:new Date().toISOString(),assets:u,hashMap:d};if(r){let p=We(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,a=n.hashMap;for(let[s,c]of Object.entries(a)){let u=i[s];if(!u||u!==c){if(r.push(`/${s}`),u&&u!==c)r.push(`/${u}`)}}for(let[s,c]of Object.entries(i))if(!a[s])r.push(`/${s}`),r.push(`/${c}`);if(r.length>100)return["/*"];return[...new Set(r)]}static updateHtmlReferences(e){let{htmlDir:n,manifest:r,basePath:i=""}=e,a=ie.collectFiles(n).filter((s)=>s.endsWith(".html")||s.endsWith(".htm"));for(let s of a){let c=Xe(s,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=[new RegExp(`(src|href)=["']${i}/?${ie.escapeRegExp(u)}["']`,"g"),new RegExp(`url\\(["']?${i}/?${ie.escapeRegExp(u)}["']?\\)`,"g")];for(let p of m)c=c.replace(p,(g)=>g.replace(u,d))}et(s,c)}}static updateCssReferences(e){let{cssDir:n,manifest:r,basePath:i=""}=e,a=ie.collectFiles(n).filter((s)=>s.endsWith(".css"));for(let s of a){let c=Xe(s,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=new RegExp(`url\\(["']?${i}/?${ie.escapeRegExp(u)}["']?\\)`,"g");c=c.replace(m,`url(${i}/${d})`)}et(s,c)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:n,keyPrefix:r="",excludePatterns:i=[],cacheControl:a={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return ie.hashDirectory({sourceDir:n,excludePatterns:i}).assets.map((c)=>{let u=c.hash!=="",d=c.contentType==="text/html",m=a.unhashed||"public, max-age=3600";if(d)m=a.html||"public, max-age=0, must-revalidate";else if(u)m=a.hashed||"public, max-age=31536000, immutable";return{localPath:We(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)),a=new Set(Object.keys(n.hashMap));for(let s of a)if(!i.has(s))r.added.push(s);for(let s of i)if(!a.has(s))r.removed.push(s);for(let s of a)if(i.has(s))if(e.hashMap[s]!==n.hashMap[s])r.changed.push(s);else r.unchanged.push(s);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 Mi{static createSecret(e){let{slug:n,environment:r,secretName:i,description:a,secretString:s,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:a,SecretString:s,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:a,excludeCharacters:s,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),C={Type:"AWS::SecretsManager::Secret",Properties:{Name:h,Description:a,GenerateSecretString:{ExcludeCharacters:s,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(([P,E])=>({Key:P,Value:E})):[]]}};if(y)C.Properties.KmsKeyId=y;return{secret:C,logicalId:S}}static createDatabaseSecret(e){let{slug:n,environment:r,secretName:i,username:a,dbname:s,engine:c,host:u,port:d,kmsKeyId:m}=e,p=i||l({slug:n,environment:r,resourceType:"db-secret"}),g=o(p),y={username:a};if(s)y.dbname=s;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 ${a}`,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:a,targetType:s}=e,c=l({slug:n,environment:r,resourceType:"secret-attachment"}),u=o(c);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:i,TargetId:a,TargetType:s}},logicalId:u}}static enableRotation(e){let{slug:n,environment:r,secretId:i,rotationLambdaArn:a,automaticallyAfterDays:s,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:s||30}}};if(a)y.Properties.RotationLambdaARN=a;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)=>Mi.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)=>Mi.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)=>Mi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,n)=>Mi.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:a,type:s="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:s,Value:a,Description:c,Tier:u,Tags:{Name:m,Environment:r,...d}}},logicalId:p}}static createString(e,n,r,i,a){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"String",description:a})}static createSecureString(e,n,r,i,a){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"SecureString",description:a})}static createStringList(e,n,r,i,a){return X.createParameter({slug:e,environment:n,parameterName:r,value:i.join(","),type:"StringList",description:a})}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 a=X.createString(e,n,"oauth-client-id",r,"OAuth client ID"),s=X.createSecureString(e,n,"oauth-client-secret",i,"OAuth client secret");return{clientId:a,clientSecret:s}},smtpCredentials:(e,n,r,i,a,s)=>{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",a,"SMTP host"),m=X.createString(e,n,"smtp-port",s.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 Kt{static createDomain(e){let{slug:n,environment:r,domainName:i,engineVersion:a="OpenSearch_2.11",instanceType:s="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:C=!0,tlsSecurityPolicy:P="Policy-Min-TLS-1-2-2019-07",advancedSecurity:E,autoSnapshotHour:v=0,autoTune:I=!0,tags:D={}}=e,N=i||l({slug:n,environment:r,resourceType:"search"}),M=o(N);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:N,EngineVersion:a,ClusterConfig:{InstanceType:s,InstanceCount:c,DedicatedMasterEnabled:m,...m&&{DedicatedMasterType:p||s,DedicatedMasterCount:g},ZoneAwarenessEnabled:y,...y&&{ZoneAwarenessConfig:{AvailabilityZoneCount:f}}},EBSOptions:{EBSEnabled:!0,VolumeType:d,VolumeSize:u},DomainEndpointOptions:{EnforceHTTPS:C,TLSSecurityPolicy:P},SnapshotOptions:{AutomatedSnapshotStartHour:v},...h&&{VPCOptions:{SubnetIds:h.subnetIds,SecurityGroupIds:h.securityGroupIds}},...S&&{EncryptionAtRestOptions:{Enabled:S.atRest??!0,...S.kmsKeyId&&{KmsKeyId:S.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:S.nodeToNode??!0}},...E&&{AdvancedSecurityOptions:{Enabled:E.enabled,InternalUserDatabaseEnabled:E.internalUserDatabase??!0,...E.masterUserName&&E.masterUserPassword&&{MasterUserOptions:{MasterUserName:E.masterUserName,MasterUserPassword:E.masterUserPassword}},...E.masterUserArn&&{MasterUserOptions:{MasterUserARN:E.masterUserArn}}}},...I&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:N},{Key:"Environment",Value:r},...Object.entries(D).map(([O,G])=>({Key:O,Value:G}))]}},logicalId:M}}static createAccessPolicy(e,n){let{ipAddresses:r,iamPrincipalArns:i,allowAll:a,vpcEndpoint:s}=n;if(a)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(s)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)=>Kt.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)=>Kt.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)=>Kt.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)=>Kt.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 It{static createDomainRedirectBucket(e){let{slug:n,environment:r,sourceDomain:i,targetDomain:a,protocol:s="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:a,Protocol:s}},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:R.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[R.Join("",[R.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:m,bucketPolicy:p,logicalId:u,policyLogicalId:d}}static createPathRedirectFunction(e){let{slug:n,environment:r,rules:i}=e,a=l({slug:n,environment:r,resourceType:"cf-redirect"}),s=o(a),c=It.generateRedirectFunctionCode(i);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:a,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${n} (${r})`,Runtime:"cloudfront-js-2.0"},FunctionCode:c}},logicalId:s,functionCode:c}}static generateRedirectFunctionCode(e){return`function handler(event) {
|
|
2281
|
+
| limit 50`,region:i,title:"Recent Errors and Warnings"}}),c+=6;return Fi.createDashboard({slug:n,environment:r,widgets:s})}static DashboardTemplates={staticWebsite:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Static Website Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"CloudFront Requests",region:"us-east-1",metrics:[["AWS/CloudFront","Requests","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"Error Rate",region:"us-east-1",metrics:[["AWS/CloudFront","4xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",e.cloudFrontDistributionId,"Region","Global",{label:"5XX"}]],period:300,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Bytes Downloaded",region:"us-east-1",metrics:[["AWS/CloudFront","BytesDownloaded","DistributionId",e.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:e.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",e.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:e.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",e.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(e)=>({slug:e.slug,environment:e.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${e.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",e.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",e.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:e.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",e.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",e.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...e.lambdaFunctionNames.map((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:a="GreaterThanThreshold",evaluationPeriods:s=1,period:c=300,statistic:u="Average",treatMissingData:d="missing"}=e;return{MetricName:n,Namespace:r,Threshold:i,ComparisonOperator:a,EvaluationPeriods:s,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:a,autoVerifiedAttributes:s,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(a&&a.length>0)S.Properties.UsernameAttributes=a;if(s&&s.length>0)S.Properties.AutoVerifiedAttributes=s;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:a,generateSecret:s=!1,refreshTokenValidity:c,accessTokenValidity:u,idTokenValidity:d,tokenValidityUnits:m,readAttributes:p,writeAttributes:g,explicitAuthFlows:y,preventUserExistenceErrors:f,enableTokenRevocation:h,callbackURLs:S,logoutURLs:C,allowedOAuthFlows:P,allowedOAuthScopes:E,allowedOAuthFlowsUserPoolClient:v,supportedIdentityProviders:I}=n,D=a||l({slug:r,environment:i,resourceType:"user-pool-client"}),N=o(D);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:D,UserPoolId:R.Ref(e),GenerateSecret:s,RefreshTokenValidity:c,AccessTokenValidity:u,IdTokenValidity:d,TokenValidityUnits:m,ReadAttributes:p,WriteAttributes:g,ExplicitAuthFlows:y,PreventUserExistenceErrors:f,EnableTokenRevocation:h,CallbackURLs:S,LogoutURLs:C,AllowedOAuthFlows:P,AllowedOAuthScopes:E,AllowedOAuthFlowsUserPoolClient:v,SupportedIdentityProviders:I}},logicalId:N}}static createUserPoolDomain(e,n){let{slug:r,environment:i,domain:a,customDomainConfig:s}=n,c=l({slug:r,environment:i,resourceType:"user-pool-domain"}),u=o(c);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:a,UserPoolId:R.Ref(e),CustomDomainConfig:s}},logicalId:u}}static createIdentityPool(e){let{slug:n,environment:r,identityPoolName:i,allowUnauthenticatedIdentities:a=!1,cognitoIdentityProviders:s,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:a,CognitoIdentityProviders:s,SupportedLoginProviders:c,SamlProviderARNs:u,OpenIdConnectProviderARNs:d}},logicalId:p}}static createIdentityPoolRoleAttachment(e,n){let{slug:r,environment:i,authenticatedRole:a,unauthenticatedRole:s,roleMappings:c}=n,u=l({slug:r,environment:i,resourceType:"identity-pool-role-attachment"}),d=o(u),m={authenticated:a};if(s)m.unauthenticated=s;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:R.Ref(e),Roles:m,RoleMappings:c}},logicalId:d}}static createAuthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,a=l({slug:n,environment:r,resourceType:"cognito-authenticated-role"}),s=o(a);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":R.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:a},{Key:"Environment",Value:r}]}},logicalId:s}}static createUnauthenticatedRole(e){let{slug:n,environment:r,identityPoolLogicalId:i}=e,a=l({slug:n,environment:r,resourceType:"cognito-unauthenticated-role"}),s=o(a);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:a,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":R.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:a},{Key:"Environment",Value:r}]}},logicalId:s}}static PasswordPolicies={relaxed:()=>({minimumLength:8,requireLowercase:!1,requireUppercase:!1,requireNumbers:!1,requireSymbols:!1,temporaryPasswordValidityDays:7}),standard:()=>({minimumLength:8,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!1,temporaryPasswordValidityDays:3}),strict:()=>({minimumLength:12,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!0,temporaryPasswordValidityDays:1})};static AuthFlows={standard:["ALLOW_USER_SRP_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],admin:["ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],custom:["ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],all:["ALLOW_USER_SRP_AUTH","ALLOW_USER_PASSWORD_AUTH","ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"]};static OAuthScopes={basic:["openid","email","profile"],all:["openid","email","profile","phone","aws.cognito.signin.user.admin"]};static UseCases={webApp:(e,n,r)=>{let{userPool:i,logicalId:a}=Pe.createUserPool({slug:e,environment:n,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:Pe.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:s,logicalId:c}=Pe.createUserPoolClient(a,{slug:e,environment:n,explicitAuthFlows:[...Pe.AuthFlows.standard],callbackURLs:[r],allowedOAuthFlows:["code"],allowedOAuthScopes:[...Pe.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:i,poolId:a,client:s,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:a,logicalId:s}=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:R.Ref(s),ProviderName:R.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:R.GetAtt(m,"Arn")});return{userPool:r,poolId:i,client:a,clientId:s,identityPool:c,identityPoolId:u,authRole:d,authRoleId:m,attachment:p,attachmentId:g}}}}import{createHash as $r}from"node:crypto";import{copyFileSync as Gr,existsSync as bt,readdirSync as _r,readFileSync as Xe,statSync as Wr,writeFileSync as et}from"node:fs";import{basename as Hr,dirname as mn,extname as pn,join as We}from"node:path";class De{static createApplication(e){let{slug:n,environment:r,applicationName:i,computePlatform:a}=e,s=i||l({slug:n,environment:r,resourceType:"deploy-app"}),c=o(s);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:s,ComputePlatform:a,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:r}]}},logicalId:c}}static createDeploymentGroup(e,n){let{slug:r,environment:i,deploymentGroupName:a,serviceRoleArn:s,autoScalingGroups:c,ec2TagFilters:u,deploymentConfigName:d,autoRollbackConfiguration:m,alarmConfiguration:p,loadBalancerInfo:g,blueGreenDeploymentConfiguration:y}=n,f=a||l({slug:r,environment:i,resourceType:"deploy-group"}),h=o(f);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:R.Ref(e),DeploymentGroupName:f,ServiceRoleArn:s,AutoScalingGroups:c,Ec2TagFilters:u?.map((C)=>({Key:C.key,Value:C.value,Type:C.type})),DeploymentConfigName:d,AutoRollbackConfiguration:m?{Enabled:m.enabled,Events:m.events}:void 0,AlarmConfiguration:p?{Enabled:p.enabled,Alarms:p.alarms?.map((C)=>({Name:C.name})),IgnorePollAlarmFailure:p.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:g?{TargetGroupInfoList:g.targetGroupInfoList?.map((C)=>({Name:C.name})),ElbInfoList:g.elbInfoList?.map((C)=>({Name:C.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:a,trafficRoutingConfig:s}=e,c=i||l({slug:n,environment:r,resourceType:"deploy-config"}),u=o(c);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:c,MinimumHealthyHosts:a?{Type:a.type,Value:a.value}:void 0,TrafficRoutingConfig:s?{Type:s.type,TimeBasedCanary:s.timeBasedCanary?{CanaryPercentage:s.timeBasedCanary.canaryPercentage,CanaryInterval:s.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:s.timeBasedLinear?{LinearPercentage:s.timeBasedLinear.linearPercentage,LinearInterval:s.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId: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:a,logicalId:s}=De.createApplication({slug:e,environment:n,computePlatform:"Server"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(s,{slug:e,environment:n,serviceRoleArn:r,autoScalingGroups:i,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:a,appId:s,deploymentGroup:c,groupId:u}},lambdaCanaryDeployment:(e,n,r,i=10,a=5)=>{let{application:s,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,a)}),{deploymentGroup:m,logicalId:p}=De.createDeploymentGroup(c,{slug:e,environment:n,serviceRoleArn:r,deploymentConfigName:R.Ref(d),autoRollbackConfiguration:De.RollbackConfigs.onAlarmOrFailure()});return{application:s,appId:c,deploymentConfig:u,configId:d,deploymentGroup:m,groupId:p}},ecsBlueGreenDeployment:(e,n,r,i)=>{let{application:a,logicalId:s}=De.createApplication({slug:e,environment:n,computePlatform:"ECS"}),{deploymentGroup:c,logicalId:u}=De.createDeploymentGroup(s,{slug:e,environment:n,serviceRoleArn:r,loadBalancerInfo:{targetGroupInfoList:[{name:i}]},blueGreenDeploymentConfiguration:De.BlueGreenConfigs.standard(),autoRollbackConfiguration:De.RollbackConfigs.onFailure()});return{application:a,appId:s,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 ie{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 ie.computeFileHash(e).slice(0,8)}static getContentType(e){let n=pn(e).toLowerCase();return ie.ContentTypes[n]||"application/octet-stream"}static shouldHashFile(e,n){return![...ie.NoHashPatterns,...n||[]].some((i)=>i.test(e))}static generateHashedFilename(e,n){let r=pn(e),i=Hr(e,r),a=mn(e);if(a===".")return`${i}.${n}${r}`;return We(a,`${i}.${n}${r}`)}static collectFiles(e,n){let r=[],i=n||e;if(!bt(e))return r;let a=_r(e,{withFileTypes:!0});for(let s of a){let c=We(e,s.name);if(s.isDirectory())r.push(...ie.collectFiles(c,i));else if(s.isFile())r.push(c)}return r}static hashDirectory(e){let{sourceDir:n,outputDir:r,excludePatterns:i=[],hashAlgorithm:a="md5",copyUnhashed:s=!0}=e,c=ie.collectFiles(n),u=[],d={};for(let p of c){let g=p.replace(n,"").replace(/^[/\\]/,""),y=ie.shouldHashFile(g,i),f=Wr(p),h=y?ie.computeFileHash(p,a).slice(0,8):"",S=y?ie.generateHashedFilename(g,h):g,C={originalPath:g,hashedPath:S,hash:h,size:f.size,contentType:ie.getContentType(p)};if(u.push(C),d[g]=S,r){let P=We(r,S),E=mn(P);if(!bt(E)){let{mkdirSync:v}=zr("node:fs");v(E,{recursive:!0})}if(y||s)Gr(p,P)}}let m={version:"1.0",timestamp:new Date().toISOString(),assets:u,hashMap:d};if(r){let p=We(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,a=n.hashMap;for(let[s,c]of Object.entries(a)){let u=i[s];if(!u||u!==c){if(r.push(`/${s}`),u&&u!==c)r.push(`/${u}`)}}for(let[s,c]of Object.entries(i))if(!a[s])r.push(`/${s}`),r.push(`/${c}`);if(r.length>100)return["/*"];return[...new Set(r)]}static updateHtmlReferences(e){let{htmlDir:n,manifest:r,basePath:i=""}=e,a=ie.collectFiles(n).filter((s)=>s.endsWith(".html")||s.endsWith(".htm"));for(let s of a){let c=Xe(s,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=[new RegExp(`(src|href)=["']${i}/?${ie.escapeRegExp(u)}["']`,"g"),new RegExp(`url\\(["']?${i}/?${ie.escapeRegExp(u)}["']?\\)`,"g")];for(let p of m)c=c.replace(p,(g)=>g.replace(u,d))}et(s,c)}}static updateCssReferences(e){let{cssDir:n,manifest:r,basePath:i=""}=e,a=ie.collectFiles(n).filter((s)=>s.endsWith(".css"));for(let s of a){let c=Xe(s,"utf-8");for(let[u,d]of Object.entries(r.hashMap)){if(u===d)continue;let m=new RegExp(`url\\(["']?${i}/?${ie.escapeRegExp(u)}["']?\\)`,"g");c=c.replace(m,`url(${i}/${d})`)}et(s,c)}}static escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(e){let{sourceDir:n,keyPrefix:r="",excludePatterns:i=[],cacheControl:a={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=e;return ie.hashDirectory({sourceDir:n,excludePatterns:i}).assets.map((c)=>{let u=c.hash!=="",d=c.contentType==="text/html",m=a.unhashed||"public, max-age=3600";if(d)m=a.html||"public, max-age=0, must-revalidate";else if(u)m=a.hashed||"public, max-age=31536000, immutable";return{localPath:We(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)),a=new Set(Object.keys(n.hashMap));for(let s of a)if(!i.has(s))r.added.push(s);for(let s of i)if(!a.has(s))r.removed.push(s);for(let s of a)if(i.has(s))if(e.hashMap[s]!==n.hashMap[s])r.changed.push(s);else r.unchanged.push(s);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 Bi{static createSecret(e){let{slug:n,environment:r,secretName:i,description:a,secretString:s,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:a,SecretString:s,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:a,excludeCharacters:s,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),C={Type:"AWS::SecretsManager::Secret",Properties:{Name:h,Description:a,GenerateSecretString:{ExcludeCharacters:s,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(([P,E])=>({Key:P,Value:E})):[]]}};if(y)C.Properties.KmsKeyId=y;return{secret:C,logicalId:S}}static createDatabaseSecret(e){let{slug:n,environment:r,secretName:i,username:a,dbname:s,engine:c,host:u,port:d,kmsKeyId:m}=e,p=i||l({slug:n,environment:r,resourceType:"db-secret"}),g=o(p),y={username:a};if(s)y.dbname=s;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 ${a}`,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:a,targetType:s}=e,c=l({slug:n,environment:r,resourceType:"secret-attachment"}),u=o(c);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:i,TargetId:a,TargetType:s}},logicalId:u}}static enableRotation(e){let{slug:n,environment:r,secretId:i,rotationLambdaArn:a,automaticallyAfterDays:s,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:s||30}}};if(a)y.Properties.RotationLambdaARN=a;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)=>Bi.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)=>Bi.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)=>Bi.createGeneratedSecret({slug:e,environment:n,secretName:`${e}-${n}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(e,n)=>Bi.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:a,type:s="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:s,Value:a,Description:c,Tier:u,Tags:{Name:m,Environment:r,...d}}},logicalId:p}}static createString(e,n,r,i,a){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"String",description:a})}static createSecureString(e,n,r,i,a){return X.createParameter({slug:e,environment:n,parameterName:r,value:i,type:"SecureString",description:a})}static createStringList(e,n,r,i,a){return X.createParameter({slug:e,environment:n,parameterName:r,value:i.join(","),type:"StringList",description:a})}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 a=X.createString(e,n,"oauth-client-id",r,"OAuth client ID"),s=X.createSecureString(e,n,"oauth-client-secret",i,"OAuth client secret");return{clientId:a,clientSecret:s}},smtpCredentials:(e,n,r,i,a,s)=>{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",a,"SMTP host"),m=X.createString(e,n,"smtp-port",s.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 Kt{static createDomain(e){let{slug:n,environment:r,domainName:i,engineVersion:a="OpenSearch_2.11",instanceType:s="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:C=!0,tlsSecurityPolicy:P="Policy-Min-TLS-1-2-2019-07",advancedSecurity:E,autoSnapshotHour:v=0,autoTune:I=!0,tags:D={}}=e,N=i||l({slug:n,environment:r,resourceType:"search"}),M=o(N);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:N,EngineVersion:a,ClusterConfig:{InstanceType:s,InstanceCount:c,DedicatedMasterEnabled:m,...m&&{DedicatedMasterType:p||s,DedicatedMasterCount:g},ZoneAwarenessEnabled:y,...y&&{ZoneAwarenessConfig:{AvailabilityZoneCount:f}}},EBSOptions:{EBSEnabled:!0,VolumeType:d,VolumeSize:u},DomainEndpointOptions:{EnforceHTTPS:C,TLSSecurityPolicy:P},SnapshotOptions:{AutomatedSnapshotStartHour:v},...h&&{VPCOptions:{SubnetIds:h.subnetIds,SecurityGroupIds:h.securityGroupIds}},...S&&{EncryptionAtRestOptions:{Enabled:S.atRest??!0,...S.kmsKeyId&&{KmsKeyId:S.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:S.nodeToNode??!0}},...E&&{AdvancedSecurityOptions:{Enabled:E.enabled,InternalUserDatabaseEnabled:E.internalUserDatabase??!0,...E.masterUserName&&E.masterUserPassword&&{MasterUserOptions:{MasterUserName:E.masterUserName,MasterUserPassword:E.masterUserPassword}},...E.masterUserArn&&{MasterUserOptions:{MasterUserARN:E.masterUserArn}}}},...I&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:N},{Key:"Environment",Value:r},...Object.entries(D).map(([O,G])=>({Key:O,Value:G}))]}},logicalId:M}}static createAccessPolicy(e,n){let{ipAddresses:r,iamPrincipalArns:i,allowAll:a,vpcEndpoint:s}=n;if(a)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(s)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)=>Kt.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)=>Kt.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)=>Kt.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)=>Kt.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 It{static createDomainRedirectBucket(e){let{slug:n,environment:r,sourceDomain:i,targetDomain:a,protocol:s="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:a,Protocol:s}},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:R.Ref(u),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[R.Join("",[R.GetAtt(u,"Arn"),"/*"])]}]}}};return{bucket:m,bucketPolicy:p,logicalId:u,policyLogicalId:d}}static createPathRedirectFunction(e){let{slug:n,environment:r,rules:i}=e,a=l({slug:n,environment:r,resourceType:"cf-redirect"}),s=o(a),c=It.generateRedirectFunctionCode(i);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:a,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${n} (${r})`,Runtime:"cloudfront-js-2.0"},FunctionCode:c}},logicalId:s,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;
|
|
@@ -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})},En={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}`)},Rm={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")qr(e,n);else if(n.type==="rest")zr(e,n);else if(n.type==="websocket")Qr(e,n)}function qr(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 zr(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}`),a=e.toLogicalId(`websocket-integration-${n}`),s=e.toLogicalId(`${r}-function`);e.addResource(a,"AWS::ApiGatewayV2::Integration",{ApiId:t.ref("WebSocketApi"),IntegrationType:"AWS_PROXY",IntegrationUri:t.sub(`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${s}.Arn}/invocations`)},{dependsOn:["WebSocketApi",s]}),e.addResource(i,"AWS::ApiGatewayV2::Route",{ApiId:t.ref("WebSocketApi"),RouteKey:n,Target:t.join("/",["integrations",t.ref(a)])},{dependsOn:["WebSocketApi",a]}),e.addResource(`${i}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(s),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*")},{dependsOn:[s,"WebSocketApi"]})}function St(e,n,r,i){let a={DomainName:r.domain};if(i==="REST")a.CertificateArn=r.certificateArn,a.EndpointConfiguration={Types:["REGIONAL"]},e.addResource("ApiCustomDomain","AWS::ApiGateway::DomainName",a),e.addResource("ApiBasePathMapping","AWS::ApiGateway::BasePathMapping",{DomainName:t.ref("ApiCustomDomain"),RestApiId:t.ref(n),Stage:t.ref("RestApiStage")},{dependsOn:["ApiCustomDomain",n,"RestApiStage"]});else a.DomainNameConfigurations=[{CertificateArn:r.certificateArn,EndpointType:"REGIONAL"}],e.addResource("ApiCustomDomain","AWS::ApiGatewayV2::DomainName",a),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 yn(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 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 a={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)a.LambdaFunctionAssociations=n.edgeFunctions.map((c)=>({EventType:c.eventType,LambdaFunctionARN:c.functionArn}));let s={Enabled:!0,HttpVersion:n.http3?"http3":"http2",IPV6Enabled:!0,Origins:r,DefaultCacheBehavior:a,PriceClass:n.priceClass||"PriceClass_100",ViewerCertificate:{}};if(i.length>0)s.CacheBehaviors=i;if(n.customDomain)s.Aliases=[n.customDomain.domain],s.ViewerCertificate={AcmCertificateArn:n.customDomain.certificateArn,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else s.ViewerCertificate={CloudFrontDefaultCertificate:!0};if(n.errorPages)s.CustomErrorResponses=Object.entries(n.errorPages).map(([c,u])=>({ErrorCode:Number.parseInt(c),ResponseCode:200,ResponsePagePath:u,ErrorCachingMinTTL:300}));if(s.DefaultRootObject="index.html",s.Comment=t.sub("${AWS::StackName} CloudFront Distribution"),e.addResource("CloudFrontDistribution","AWS::CloudFront::Distribution",{DistributionConfig:s},{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 bn(e,n){if(n.server)ni(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 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})},wn={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}`)},Rm={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")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}`),a=e.toLogicalId(`websocket-integration-${n}`),s=e.toLogicalId(`${r}-function`);e.addResource(a,"AWS::ApiGatewayV2::Integration",{ApiId:t.ref("WebSocketApi"),IntegrationType:"AWS_PROXY",IntegrationUri:t.sub(`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${s}.Arn}/invocations`)},{dependsOn:["WebSocketApi",s]}),e.addResource(i,"AWS::ApiGatewayV2::Route",{ApiId:t.ref("WebSocketApi"),RouteKey:n,Target:t.join("/",["integrations",t.ref(a)])},{dependsOn:["WebSocketApi",a]}),e.addResource(`${i}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(s),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${WebSocketApi}/*")},{dependsOn:[s,"WebSocketApi"]})}function St(e,n,r,i){let a={DomainName:r.domain};if(i==="REST")a.CertificateArn=r.certificateArn,a.EndpointConfiguration={Types:["REGIONAL"]},e.addResource("ApiCustomDomain","AWS::ApiGateway::DomainName",a),e.addResource("ApiBasePathMapping","AWS::ApiGateway::BasePathMapping",{DomainName:t.ref("ApiCustomDomain"),RestApiId:t.ref(n),Stage:t.ref("RestApiStage")},{dependsOn:["ApiCustomDomain",n,"RestApiStage"]});else a.DomainNameConfigurations=[{CertificateArn:r.certificateArn,EndpointType:"REGIONAL"}],e.addResource("ApiCustomDomain","AWS::ApiGatewayV2::DomainName",a),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 yn(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 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 a={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)a.LambdaFunctionAssociations=n.edgeFunctions.map((c)=>({EventType:c.eventType,LambdaFunctionARN:c.functionArn}));let s={Enabled:!0,HttpVersion:n.http3?"http3":"http2",IPV6Enabled:!0,Origins:r,DefaultCacheBehavior:a,PriceClass:n.priceClass||"PriceClass_100",ViewerCertificate:{}};if(i.length>0)s.CacheBehaviors=i;if(n.customDomain)s.Aliases=[n.customDomain.domain],s.ViewerCertificate={AcmCertificateArn:n.customDomain.certificateArn,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};else s.ViewerCertificate={CloudFrontDefaultCertificate:!0};if(n.errorPages)s.CustomErrorResponses=Object.entries(n.errorPages).map(([c,u])=>({ErrorCode:Number.parseInt(c),ResponseCode:200,ResponsePagePath:u,ErrorCachingMinTTL:300}));if(s.DefaultRootObject="index.html",s.Comment=t.sub("${AWS::StackName} CloudFront Distribution"),e.addResource("CloudFrontDistribution","AWS::CloudFront::Distribution",{DistributionConfig:s},{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 bn(e,n){if(n.server)ni(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 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
|
|
2434
2434
|
set -e
|
|
2435
2435
|
# Update system
|
|
2436
2436
|
yum update -y || apt-get update -y
|
|
@@ -2445,20 +2445,20 @@ 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 hn(e,n,r){let i=e.toLogicalId(n),a=r.taskDefinition.containerDefinitions?.[0],s=a?.name||a?.Name||n,c=a?.portMappings?.[0]?.containerPort||a?.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:s,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 Dn(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)=>{ii(e,r)})}function Sn(e,n,r){if(!r)return;let i=n==="postgres"?"postgres":"mysql",a=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 s=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:s,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(a,"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(a),TargetType:"AWS::RDS::DBInstance"},{dependsOn:[a,"DBSecret"]}),e.addOutputs({DBEndpoint:{Description:"Database endpoint",Value:t.getAtt(a,"Endpoint.Address"),Export:{Name:t.sub("${AWS::StackName}-db-endpoint")}},DBPort:{Description:"Database port",Value:t.getAtt(a,"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((a)=>{let s=new Set(i.AttributeDefinitions.map((u)=>u.AttributeName));if(!s.has(a.partitionKey))i.AttributeDefinitions.push({AttributeName:a.partitionKey,AttributeType:"S"});if(a.sortKey&&!s.has(a.sortKey))i.AttributeDefinitions.push({AttributeName:a.sortKey,AttributeType:"S"});let c={IndexName:a.name,KeySchema:[{AttributeName:a.partitionKey,KeyType:"HASH"}],Projection:{ProjectionType:a.projectionType||"ALL"}};if(a.sortKey)c.KeySchema.push({AttributeName:a.sortKey,KeyType:"RANGE"});if(a.projectionType==="INCLUDE"&&a.nonKeyAttributes)c.Projection.NonKeyAttributes=a.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 Nn(e,n){for(let[r,i]of Object.entries(n))i.forEach((a)=>{ai(e,a,r)})}function ai(e,n,r){let i=e.toLogicalId(`${r}-${n.name}-function`),a=`${i}Role`;e.addResource(a,"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 s={FunctionName:t.sub(`\${AWS::StackName}-${n.name}`),Runtime:n.runtime,Handler:n.handler,Role:t.getAtt(a,"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){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 hn(e,n,r){let i=e.toLogicalId(n),a=r.taskDefinition.containerDefinitions?.[0],s=a?.name||a?.Name||n,c=a?.portMappings?.[0]?.containerPort||a?.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:s,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 vn(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)=>{ii(e,r)})}function Sn(e,n,r){if(!r)return;let i=n==="postgres"?"postgres":"mysql",a=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 s=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:s,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(a,"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(a),TargetType:"AWS::RDS::DBInstance"},{dependsOn:[a,"DBSecret"]}),e.addOutputs({DBEndpoint:{Description:"Database endpoint",Value:t.getAtt(a,"Endpoint.Address"),Export:{Name:t.sub("${AWS::StackName}-db-endpoint")}},DBPort:{Description:"Database port",Value:t.getAtt(a,"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((a)=>{let s=new Set(i.AttributeDefinitions.map((u)=>u.AttributeName));if(!s.has(a.partitionKey))i.AttributeDefinitions.push({AttributeName:a.partitionKey,AttributeType:"S"});if(a.sortKey&&!s.has(a.sortKey))i.AttributeDefinitions.push({AttributeName:a.sortKey,AttributeType:"S"});let c={IndexName:a.name,KeySchema:[{AttributeName:a.partitionKey,KeyType:"HASH"}],Projection:{ProjectionType:a.projectionType||"ALL"}};if(a.sortKey)c.KeySchema.push({AttributeName:a.sortKey,KeyType:"RANGE"});if(a.projectionType==="INCLUDE"&&a.nonKeyAttributes)c.Projection.NonKeyAttributes=a.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 Nn(e,n){for(let[r,i]of Object.entries(n))i.forEach((a)=>{ai(e,a,r)})}function ai(e,n,r){let i=e.toLogicalId(`${r}-${n.name}-function`),a=`${i}Role`;e.addResource(a,"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 s={FunctionName:t.sub(`\${AWS::StackName}-${n.name}`),Runtime:n.runtime,Handler:n.handler,Role:t.getAtt(a,"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")s.VpcConfig={SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],SecurityGroupIds:[t.ref("AppSecurityGroup")]};if(e.addResource(i,"AWS::Lambda::Function",s,{dependsOn:a}),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)=>{si(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 si(e,n,r,i){let a=`${n}EventSource${i}`;switch(r.type){case"http":break;case"s3":if(r.bucket){let s=e.toLogicalId(`${r.bucket}-bucket`);e.addResource(`${a}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(n),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:
|
|
2451
|
+
};`},Environment:n.environment?{Variables:n.environment}:void 0,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n.name}`)}]};if(r!=="edge")s.VpcConfig={SubnetIds:[t.ref("PrivateSubnet1"),t.ref("PrivateSubnet2")],SecurityGroupIds:[t.ref("AppSecurityGroup")]};if(e.addResource(i,"AWS::Lambda::Function",s,{dependsOn:a}),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)=>{si(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 si(e,n,r,i){let a=`${n}EventSource${i}`;switch(r.type){case"http":break;case"s3":if(r.bucket){let s=e.toLogicalId(`${r.bucket}-bucket`);e.addResource(`${a}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(n),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:wn.s3Bucket(t.ref(s))},{dependsOn:[n,s]})}break;case"sqs":if(r.queueName){let s=e.toLogicalId(`${r.queueName}-queue`);e.addResource(a,"AWS::Lambda::EventSourceMapping",{EventSourceArn:t.getAtt(s,"Arn"),FunctionName:t.ref(n),BatchSize:r.batchSize||10},{dependsOn:[n,s]})}break;case"kinesis":if(r.streamName){let s=e.toLogicalId(`${r.streamName}-stream`);e.addResource(a,"AWS::Lambda::EventSourceMapping",{EventSourceArn:t.getAtt(s,"Arn"),FunctionName:t.ref(n),BatchSize:r.batchSize||100,StartingPosition:r.startingPosition||"LATEST",ParallelizationFactor:r.parallelizationFactor||1},{dependsOn:[n,s]})}break;case"dynamodb-stream":if(r.tableName){let s=e.toLogicalId(`${r.tableName}-table`);e.addResource(a,"AWS::Lambda::EventSourceMapping",{EventSourceArn:t.getAtt(s,"StreamArn"),FunctionName:t.ref(n),BatchSize:r.batchSize||100,StartingPosition:r.startingPosition||"LATEST"},{dependsOn:[n,s]})}break;case"schedule":if(r.expression)e.addResource(`${a}Rule`,"AWS::Events::Rule",{ScheduleExpression:r.expression,State:"ENABLED",Targets:[{Arn:t.getAtt(n,"Arn"),Id:`${n}Target`}]},{dependsOn:n}),e.addResource(`${a}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(n),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.getAtt(`${a}Rule`,"Arn")},{dependsOn:[n,`${a}Rule`]});break}}function oi(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?wn.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?wn.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 xn(e,n){if(n.topics)n.topics.forEach((r)=>{ci(e,r)})}function ci(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,a)=>{let s=`${r}Subscription${a+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(`${s}Permission`,"AWS::Lambda::Permission",{FunctionName:t.ref(u),Action:"lambda:InvokeFunction",Principal:"sns.amazonaws.com",SourceArn:t.ref(r)},{dependsOn:[u,r]})}e.addResource(s,"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 kn(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)=>{li(e,r,i)});if(n.dashboard)ui(e,n.dashboard);if(n.logs?.groups)n.logs.groups.forEach((r)=>{di(e,r,n.logs?.retention)})}function li(e,n,r){let i=e.toLogicalId(`alarm-${n.name||n.metric}-${r}`),a={AlarmName:n.name||t.sub(`\${AWS::StackName}-${n.metric}`),AlarmDescription:`Alarm for ${n.metric}`,MetricName:n.metric,Namespace:n.namespace||Ct(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)a.Dimensions=Object.entries(n.dimensions).map(([s,c])=>({Name:s,Value:c}));else if(n.service)a.Dimensions=mi(n.service);e.addResource(i,"AWS::CloudWatch::Alarm",a,{dependsOn:"AlarmTopic"})}function ui(e,n){if(!n)return;let r=[],i=0,a=0;n.widgets?.forEach((s)=>{let c=s.width||12,u=s.height||6;if(s.type==="metric"&&s.metrics){let d=s.metrics.map((m)=>{if(typeof m==="string")return[Ct(m),m];else return[Ct(m.metric,m.service),m.metric]});r.push({type:"metric",x:i,y:a,width:c,height:u,properties:{metrics:d,period:300,stat:"Average",region:t.ref("AWS::Region"),title:s.metrics.length>1?"Multiple Metrics":typeof s.metrics[0]==="string"?s.metrics[0]:s.metrics[0].metric}})}else if(s.type==="log"&&s.logGroup)r.push({type:"log",x:i,y:a,width:c,height:u,properties:{query:`SOURCE '${s.logGroup}'
|
|
2452
2452
|
| fields @timestamp, @message
|
|
2453
2453
|
| sort @timestamp desc
|
|
2454
|
-
| limit 20`,region:t.ref("AWS::Region"),title:`Logs: ${s.logGroup}`}});else if(s.type==="text"&&s.text)r.push({type:"text",x:i,y:a,width:c,height:u,properties:{markdown:s.text}});if(i+=c,i>=24)i=0,a+=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 Ct(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 Mn(e,n){if(!n.vpc)return;let{cidr:r="10.0.0.0/16",availabilityZones:i=2,natGateways:a=1,enableDnsHostnames:s=!0,enableDnsSupport:c=!0}=n.vpc;e.addResource("VPC","AWS::EC2::VPC",{CidrBlock:r,EnableDnsHostnames:s,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<a;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<a;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%a;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 Ln(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`),a=r.fifo||!1,s;if(r.deadLetterQueue){let u=`${i}DLQ`;e.addResource(u,"AWS::SQS::Queue",{QueueName:a?t.sub(`\${AWS::StackName}-${n}-dlq.fifo`):t.sub(`\${AWS::StackName}-${n}-dlq`),FifoQueue:a,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}-dlq`)}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),s=t.getAtt(u,"Arn")}let c={QueueName:a?t.sub(`\${AWS::StackName}-${n}.fifo`):t.sub(`\${AWS::StackName}-${n}`),FifoQueue:a,VisibilityTimeout:r.visibilityTimeout||30,MessageRetentionPeriod:r.messageRetentionPeriod||345600,ReceiveMessageWaitTimeSeconds:r.receiveMessageWaitTime||0,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}`)}]};if(a&&r.contentBasedDeduplication)c.ContentBasedDeduplication=!0;if(r.deadLetterQueue&&s)c.RedrivePolicy={deadLetterTargetArn:s,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 On(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 a=r.length+1;if(i.includes("sqlInjection"))r.push({Name:"AWSManagedRulesSQLi",Priority:a++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesSQLiRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesSQLi"}});if(i.includes("xss"))r.push({Name:"AWSManagedRulesXSS",Priority:a++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesXSS"}});if(i.includes("knownBadInputs"))r.push({Name:"AWSManagedRulesKnownBadInputs",Priority:a++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesKnownBadInputs"}});if(i.includes("coreRuleSet"))r.push({Name:"AWSManagedRulesCoreRuleSet",Priority:a++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesCommonRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesCoreRuleSet"}});if(i.includes("linuxRuleSet"))r.push({Name:"AWSManagedRulesLinuxRuleSet",Priority:a++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesLinuxRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesLinuxRuleSet"}});if(i.includes("apiProtection"))r.push({Name:"AWSManagedRulesAPIProtection",Priority:a++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesAmazonIpReputationList"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesAPIProtection"}});if(i.includes("geoBlock"))r.push({Name:"GeoBlockRule",Priority:a++,Statement:{GeoMatchStatement:{CountryCodes:["CN","RU"]}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"GeoBlockRule"}});if(i.includes("connectionLimit"))r.push({Name:"ConnectionLimitRule",Priority:a++,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`),a=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}))||[],s=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:a,SecurityGroupEgress:s,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"){bi(e,r,i);continue}hi(e,r,i)}}function hi(e,n,r){let i=e.toLogicalId(`${n}-bucket`),a={BucketName:t.sub(`\${AWS::StackName}-${n}`),Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}`)}]};if(r.versioning)a.VersioningConfiguration={Status:"Enabled"};if(r.encryption)a.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(!r.public)a.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(r.website)a.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"index.html"};if(r.cors&&r.cors.length>0)a.CorsConfiguration={CorsRules:r.cors.map((s)=>({AllowedOrigins:s.allowedOrigins,AllowedMethods:s.allowedMethods,AllowedHeaders:s.allowedHeaders||["*"],MaxAge:s.maxAge||3600}))};if(r.lifecycleRules&&r.lifecycleRules.length>0)a.LifecycleConfiguration={Rules:r.lifecycleRules.map((s)=>({Id:s.id,Status:s.enabled?"Enabled":"Disabled",ExpirationInDays:s.expirationDays,Transitions:s.transitions?.map((c)=>({TransitionInDays:c.days,StorageClass:c.storageClass}))}))};if(r.intelligentTiering)a.IntelligentTieringConfigurations=[{Id:"EntireBucket",Status:"Enabled",Tierings:[{AccessTier:"ARCHIVE_ACCESS",Days:90},{AccessTier:"DEEP_ARCHIVE_ACCESS",Days:180}]}];if(e.addResource(i,"AWS::S3::Bucket",a,{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("",[En.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`),a={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(a.LifecyclePolicies=[],r.lifecyclePolicy.transitionToIA)a.LifecyclePolicies.push({TransitionToIA:`AFTER_${r.lifecyclePolicy.transitionToIA}_DAYS`});if(r.lifecyclePolicy.transitionToPrimaryStorageClass)a.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"})}e.addResource(i,"AWS::EFS::FileSystem",a,{deletionPolicy:"Retain"});let s=2;for(let c=0;c<s;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 ll{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 a={Type:n,Properties:r};if(i?.dependsOn)a.DependsOn=i.dependsOn,this.trackDependency(e,i.dependsOn);if(i?.condition)a.Condition=i.condition;if(i?.deletionPolicy)a.DeletionPolicy=i.deletionPolicy;if(i?.updateReplacePolicy)a.UpdateReplacePolicy=i.updateReplacePolicy;this.template.Resources[e]=a}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 a=this.resourceDependencies.get(i);if(a)for(let s of a)r(s);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){Mn(this,e)}addStorageResources(e){$n(this,e)}addComputeResources(e){bn(this,e)}addDatabaseResources(e){Dn(this,e)}addFunctionResources(e){Nn(this,e)}addCacheResources(e){yn(this,e)}addQueueResources(e){Ln(this,e)}addMessagingResources(e){xn(this,e)}addCDNResources(e){fn(this,e)}addApiGatewayResources(e){gn(this,e)}addMonitoringResources(e){kn(this,e)}addSecurityResources(e){On(this,e)}}function Ea(e){return new ll(e).build()}function Im(e){let{name:n,slug:r,domain:i,subdomain:a}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:a&&i?`${a}.${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:a&&i?`${a}.${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 Pm(e){let{name:n,slug:r,domain:i,instanceType:a="t3.small",minInstances:s=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:a,ami:"ubuntu-22.04",keyPair:`${r}-key`,autoScaling:{min:s,max:c,desired:s,targetCPU:70},loadBalancer:{type:"application",healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3}},userData:{packages:["nodejs","npm","nginx"],commands:["curl -fsSL https://bun.sh/install | bash","npm install -g pm2"]}}},databases:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.micro",allocatedStorage:20,multiAZ:!0,backupRetentionDays:7,deletionProtection:!0}},cache:{redis:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},security:{certificate:i?{domain:i,subdomains:[`*.${i}`],validationMethod:"DNS"}:void 0}}}}function Dm(e){let{name:n,slug:r,domain:i,taskCpu:a="256",taskMemory:s="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:a,memory:s,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 km(e){let{name:n,slug:r,entry:i,domain:a,runtime:s="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:a,app:{kind:"node",runtime:s,entry:i,memory:c,build:u,deploy:d,assets:m,queues:p,scheduler:g,domain:a}}}}}function wa(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 Nm(e){let{name:n,slug:r,domain:i,apiSubdomain:a="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:`${a}.${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 xm(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 _m(e){let{name:n,slug:r,domain:i,instanceType:a="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:a,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 Om(e){let{name:n,slug:r,domain:i,apiDomain:a}=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},...a?{api:{runtime:"nodejs20.x",handler:"dist/api/index.handler",memory:1024,timeout:30,events:[{type:"http",path:"/{proxy+}",method:"ANY"}]}}:{}},apiGateway:a?{type:"HTTP",customDomain:{domain:a,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:a?[a]:[],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","geoBlock"]}}}}}function $m(e){let{name:n,slug:r,domain:i,services:a}=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:a.map((s)=>({name:s.name,type:"fargate",taskDefinition:{cpu:s.cpu||"256",memory:s.memory||"512",containerDefinitions:[{name:s.name,image:`${r}-${s.name}:latest`,portMappings:[{containerPort:s.port}],healthCheck:{command:["CMD-SHELL",`curl -f http://localhost:${s.port}/health || exit 1`],interval:30,timeout:5,retries:3}}]},service:{desiredCount:s.desiredCount||2,serviceDiscovery:{enabled:!0,namespace:`${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:a.map((s)=>({path:`/${s.name}/{proxy+}`,integration:{type:"vpc-link",service:s.name}}))},databases:{dynamodb:{tables:Object.fromEntries(a.map((s)=>[`${r}-${s.name}`,{partitionKey:{name:"id",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0}]))}},queues:{events:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0}},messaging:{topics:{events:{name:`${r}-events`,subscriptions:a.map((s)=>({protocol:"sqs",endpoint:`${r}-${s.name}-queue`,filterPolicy:{service:[s.name]}}))}}},monitoring:{dashboard:{name:`${r}-microservices`,widgets:a.map((s)=>({type:"metric",metrics:[{service:s.name,metric:"CPUUtilization"},{service:s.name,metric:"MemoryUtilization"},{service:s.name,metric:"RequestCount"}]}))},alarms:a.flatMap((s)=>[{name:`${s.name}-high-cpu`,metric:"CPUUtilization",threshold:80,service:s.name},{name:`${s.name}-errors`,metric:"Errors",threshold:10,service:s.name}])},security:{certificate:{domain:i,validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}}}}}function Lm(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 Mm(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 Um(e){let{name:n,slug:r,domain:i,modelS3Path:a=`s3://${r}-models/`,instanceType:s="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:a,instanceType:s,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 Fm(e){let{name:n,slug:r,domain:i,instanceType:a="t3.medium",minInstances:s=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:a,ami:"ubuntu-22.04",autoScaling:{min:s,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: ${s.logGroup}`}});else if(s.type==="text"&&s.text)r.push({type:"text",x:i,y:a,width:c,height:u,properties:{markdown:s.text}});if(i+=c,i>=24)i=0,a+=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 Ct(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 Mn(e,n){if(!n.vpc)return;let{cidr:r="10.0.0.0/16",availabilityZones:i=2,natGateways:a=1,enableDnsHostnames:s=!0,enableDnsSupport:c=!0}=n.vpc;e.addResource("VPC","AWS::EC2::VPC",{CidrBlock:r,EnableDnsHostnames:s,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<a;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<a;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%a;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 Ln(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`),a=r.fifo||!1,s;if(r.deadLetterQueue){let u=`${i}DLQ`;e.addResource(u,"AWS::SQS::Queue",{QueueName:a?t.sub(`\${AWS::StackName}-${n}-dlq.fifo`):t.sub(`\${AWS::StackName}-${n}-dlq`),FifoQueue:a,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}-dlq`)}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),s=t.getAtt(u,"Arn")}let c={QueueName:a?t.sub(`\${AWS::StackName}-${n}.fifo`):t.sub(`\${AWS::StackName}-${n}`),FifoQueue:a,VisibilityTimeout:r.visibilityTimeout||30,MessageRetentionPeriod:r.messageRetentionPeriod||345600,ReceiveMessageWaitTimeSeconds:r.receiveMessageWaitTime||0,Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}`)}]};if(a&&r.contentBasedDeduplication)c.ContentBasedDeduplication=!0;if(r.deadLetterQueue&&s)c.RedrivePolicy={deadLetterTargetArn:s,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 On(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 a=r.length+1;if(i.includes("sqlInjection"))r.push({Name:"AWSManagedRulesSQLi",Priority:a++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesSQLiRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesSQLi"}});if(i.includes("xss"))r.push({Name:"AWSManagedRulesXSS",Priority:a++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesXSS"}});if(i.includes("knownBadInputs"))r.push({Name:"AWSManagedRulesKnownBadInputs",Priority:a++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesKnownBadInputs"}});if(i.includes("coreRuleSet"))r.push({Name:"AWSManagedRulesCoreRuleSet",Priority:a++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesCommonRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesCoreRuleSet"}});if(i.includes("linuxRuleSet"))r.push({Name:"AWSManagedRulesLinuxRuleSet",Priority:a++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesLinuxRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesLinuxRuleSet"}});if(i.includes("apiProtection"))r.push({Name:"AWSManagedRulesAPIProtection",Priority:a++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesAmazonIpReputationList"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesAPIProtection"}});if(i.includes("geoBlock"))r.push({Name:"GeoBlockRule",Priority:a++,Statement:{GeoMatchStatement:{CountryCodes:["CN","RU"]}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"GeoBlockRule"}});if(i.includes("connectionLimit"))r.push({Name:"ConnectionLimitRule",Priority:a++,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`),a=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}))||[],s=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:a,SecurityGroupEgress:s,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"){bi(e,r,i);continue}hi(e,r,i)}}function hi(e,n,r){let i=e.toLogicalId(`${n}-bucket`),a={BucketName:t.sub(`\${AWS::StackName}-${n}`),Tags:[{Key:"Name",Value:t.sub(`\${AWS::StackName}-${n}`)}]};if(r.versioning)a.VersioningConfiguration={Status:"Enabled"};if(r.encryption)a.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(!r.public)a.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(r.website)a.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"index.html"};if(r.cors&&r.cors.length>0)a.CorsConfiguration={CorsRules:r.cors.map((s)=>({AllowedOrigins:s.allowedOrigins,AllowedMethods:s.allowedMethods,AllowedHeaders:s.allowedHeaders||["*"],MaxAge:s.maxAge||3600}))};if(r.lifecycleRules&&r.lifecycleRules.length>0)a.LifecycleConfiguration={Rules:r.lifecycleRules.map((s)=>({Id:s.id,Status:s.enabled?"Enabled":"Disabled",ExpirationInDays:s.expirationDays,Transitions:s.transitions?.map((c)=>({TransitionInDays:c.days,StorageClass:c.storageClass}))}))};if(r.intelligentTiering)a.IntelligentTieringConfigurations=[{Id:"EntireBucket",Status:"Enabled",Tierings:[{AccessTier:"ARCHIVE_ACCESS",Days:90},{AccessTier:"DEEP_ARCHIVE_ACCESS",Days:180}]}];if(e.addResource(i,"AWS::S3::Bucket",a,{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("",[wn.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`),a={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(a.LifecyclePolicies=[],r.lifecyclePolicy.transitionToIA)a.LifecyclePolicies.push({TransitionToIA:`AFTER_${r.lifecyclePolicy.transitionToIA}_DAYS`});if(r.lifecyclePolicy.transitionToPrimaryStorageClass)a.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"})}e.addResource(i,"AWS::EFS::FileSystem",a,{deletionPolicy:"Retain"});let s=2;for(let c=0;c<s;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 ll{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 a={Type:n,Properties:r};if(i?.dependsOn)a.DependsOn=i.dependsOn,this.trackDependency(e,i.dependsOn);if(i?.condition)a.Condition=i.condition;if(i?.deletionPolicy)a.DeletionPolicy=i.deletionPolicy;if(i?.updateReplacePolicy)a.UpdateReplacePolicy=i.updateReplacePolicy;this.template.Resources[e]=a}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 a=this.resourceDependencies.get(i);if(a)for(let s of a)r(s);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){Mn(this,e)}addStorageResources(e){$n(this,e)}addComputeResources(e){bn(this,e)}addDatabaseResources(e){vn(this,e)}addFunctionResources(e){Nn(this,e)}addCacheResources(e){yn(this,e)}addQueueResources(e){Ln(this,e)}addMessagingResources(e){xn(this,e)}addCDNResources(e){fn(this,e)}addApiGatewayResources(e){gn(this,e)}addMonitoringResources(e){kn(this,e)}addSecurityResources(e){On(this,e)}}function Ea(e){return new ll(e).build()}function Im(e){let{name:n,slug:r,domain:i,subdomain:a}=e;return{project:{name:n,slug:r,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:a&&i?`${a}.${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:a&&i?`${a}.${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 Pm(e){let{name:n,slug:r,domain:i,instanceType:a="t3.small",minInstances:s=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:a,ami:"ubuntu-22.04",keyPair:`${r}-key`,autoScaling:{min:s,max:c,desired:s,targetCPU:70},loadBalancer:{type:"application",healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3}},userData:{packages:["nodejs","npm","nginx"],commands:["curl -fsSL https://bun.sh/install | bash","npm install -g pm2"]}}},databases:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.micro",allocatedStorage:20,multiAZ:!0,backupRetentionDays:7,deletionProtection:!0}},cache:{redis:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},security:{certificate:i?{domain:i,subdomains:[`*.${i}`],validationMethod:"DNS"}:void 0}}}}function Dm(e){let{name:n,slug:r,domain:i,taskCpu:a="256",taskMemory:s="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:a,memory:s,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 km(e){let{name:n,slug:r,entry:i,domain:a,runtime:s="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:a,app:{kind:"node",runtime:s,entry:i,memory:c,build:u,deploy:d,assets:m,queues:p,scheduler:g,domain:a}}}}}function wa(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 Nm(e){let{name:n,slug:r,domain:i,apiSubdomain:a="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:`${a}.${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 xm(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 _m(e){let{name:n,slug:r,domain:i,instanceType:a="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:a,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 Om(e){let{name:n,slug:r,domain:i,apiDomain:a}=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},...a?{api:{runtime:"nodejs20.x",handler:"dist/api/index.handler",memory:1024,timeout:30,events:[{type:"http",path:"/{proxy+}",method:"ANY"}]}}:{}},apiGateway:a?{type:"HTTP",customDomain:{domain:a,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:a?[a]:[],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","geoBlock"]}}}}}function $m(e){let{name:n,slug:r,domain:i,services:a}=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:a.map((s)=>({name:s.name,type:"fargate",taskDefinition:{cpu:s.cpu||"256",memory:s.memory||"512",containerDefinitions:[{name:s.name,image:`${r}-${s.name}:latest`,portMappings:[{containerPort:s.port}],healthCheck:{command:["CMD-SHELL",`curl -f http://localhost:${s.port}/health || exit 1`],interval:30,timeout:5,retries:3}}]},service:{desiredCount:s.desiredCount||2,serviceDiscovery:{enabled:!0,namespace:`${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:a.map((s)=>({path:`/${s.name}/{proxy+}`,integration:{type:"vpc-link",service:s.name}}))},databases:{dynamodb:{tables:Object.fromEntries(a.map((s)=>[`${r}-${s.name}`,{partitionKey:{name:"id",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0}]))}},queues:{events:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0}},messaging:{topics:{events:{name:`${r}-events`,subscriptions:a.map((s)=>({protocol:"sqs",endpoint:`${r}-${s.name}-queue`,filterPolicy:{service:[s.name]}}))}}},monitoring:{dashboard:{name:`${r}-microservices`,widgets:a.map((s)=>({type:"metric",metrics:[{service:s.name,metric:"CPUUtilization"},{service:s.name,metric:"MemoryUtilization"},{service:s.name,metric:"RequestCount"}]}))},alarms:a.flatMap((s)=>[{name:`${s.name}-high-cpu`,metric:"CPUUtilization",threshold:80,service:s.name},{name:`${s.name}-errors`,metric:"Errors",threshold:10,service:s.name}])},security:{certificate:{domain:i,validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}}}}}function Lm(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 Mm(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 Um(e){let{name:n,slug:r,domain:i,modelS3Path:a=`s3://${r}-models/`,instanceType:s="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:a,instanceType:s,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 Fm(e){let{name:n,slug:r,domain:i,instanceType:a="t3.medium",minInstances:s=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:a,ami:"ubuntu-22.04",autoScaling:{min:s,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 Bm(e){let{name:n,slug:r,domain:i,repository:a,phpVersion:s="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:[s],default:s},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:u,username:u,password:d}},sites:{main:{root:".",type:"laravel",domain:i,phpVersion:s,repository:{...a,strategy:p},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:m}}}}}function jm(e){let{name:n,slug:r,domain:i,layers:a,phpVersion:s="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:s,architecture:c,layers:a,memory:u,build:d,deploy:m,assets:"public",queues:!0,scheduler:g,cache:{driver:p},domain:i}}}}}function Vm(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 du=sa,uu="./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 pu=20000,mu=12000;function gu(e){return pu+Ai(e)%mu}function Bn(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 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 a of Object.values(e.sites??{})){let s=a;if(!s||s.redirect)continue;let c=s.domain;if(typeof c==="string")r.push(c);else if(Array.isArray(c))r.push(...c.filter((u)=>typeof u==="string"))}return r.filter((a)=>a&&!a.startsWith("dashboard."))}function fu(e,n,r){if(r)return r;let i=Fn(e,n),a=i[0];if(!a)return null;return Bn(a,i)}function hu(e,n,r){if(r)return[r];let i=Fn(e,n),a=[];for(let s of i){let c=Bn(s,i);if(!a.includes(c))a.push(c)}return a}function Jt(e){return Object.entries(e.sites??{}).some(([n,r])=>{if(!r)return!1;let i=r.root??"";return
|
|
2459
|
-
`),i=null,a,s,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&&a&&s)return{accessKeyId:a,secretAccessKey:s,sessionToken:c};i=m[1],a=void 0,s=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":a=y;break;case"aws_secret_access_key":s=y;break;case"aws_session_token":c=y;break}}}if(i===n&&a&&s)return{accessKeyId:a,secretAccessKey:s,sessionToken:c};return null}async function Su(e){let n=e?.timeout??1000,r="http://169.254.169.254";try{let i=await Ke("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 a=await i.text(),s=await Ke("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":a}},n);if(!s.ok)return null;let c=(await s.text()).trim(),u=await Ke(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${c}`,{headers:{"X-aws-ec2-metadata-token":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 vu(e){let n=e?.timeout??1000,r=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,i=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,a=null;if(r)a=`http://169.254.170.2${r}`;else if(i)a=i;if(!a)return null;try{let s={},c=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(c)s.Authorization=c;let u=await Ke(a,{headers: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 Cu(e){let n=e?.timeout??5000,r=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,i=process.env.AWS_ROLE_ARN,a=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!r||!i)return null;try{let s=Tt(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:a,WebIdentityToken:s}),m=await Ke(`${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
|
|
2460
|
-
`),u=!1;for(let d of c){let m=d.trim();if(m.startsWith("[")){u=m===s;continue}if(u&&m.startsWith("region")){let[,p]=m.split("=");if(p)return p.trim()}}}catch{}return"us-east-1"}async function ml(e){let n=e||await
|
|
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 a={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[n];if(!a)throw Error(`Unknown waiter: ${n}`);return this.waitForStack(e,a,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,[a,s]]of Object.entries(e.parameters).entries())n[`Parameters.member.${i+1}.ParameterKey`]=a,n[`Parameters.member.${i+1}.ParameterValue`]=s;if(e.capabilities)for(let[i,a]of e.capabilities.entries())n[`Capabilities.member.${i+1}`]=a;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,a=Array.isArray(i)?i[0]:i;if(!a)return{};let s={},c=a.Outputs?.member;if(c){let u=Array.isArray(c)?c:[c];for(let d of u)if(d.OutputKey&&d.OutputValue)s[d.OutputKey]=d.OutputValue}return s}}function Et(e,n=""){let r={};for(let[i,a]of Object.entries(e)){let s=n?`${n}.${i}`:i;if(Array.isArray(a))a.forEach((c,u)=>{if(typeof c==="object")Object.assign(r,Et(c,`${s}.${u+1}`));else r[`${s}.${u+1}`]=String(c)});else if(typeof a==="object"&&a!==null)Object.assign(r,Et(a,s));else if(a!==void 0&&a!==null)r[s]=String(a)}return r}function vi(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function n(a,s,c){let u=1,d=c,m=`<${s}`,p=`</${s}>`;while(d<a.length&&u>0){let g=a.indexOf(m,d),y=a.indexOf(p,d);if(y===-1)return-1;if(g!==-1&&g<y){let f=a[g+m.length];if(f===">"||f===" "||f==="/"){let h=a.indexOf(">",g);if(h!==-1&&a[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(a,s){while(s<a.length&&/\s/.test(a[s]))s++;if(s>=a.length||a[s]!=="<"){let S=a.indexOf("<",s);if(S===-1)return{value:a.slice(s).trim(),end:a.length};return{value:a.slice(s,S).trim(),end:S}}if(a[s+1]==="/")return{value:void 0,end:s};let c=a.slice(s).match(/^<(\w+)([^>]*?)\/?>/);if(!c)return{value:void 0,end:s+1};let u=c[1];if(c[0].endsWith("/>"))return{value:"",end:s+c[0].length};let m=s+c[0].length,p=`</${u}>`,g=n(a,u,m);if(g===-1)return{value:void 0,end:s+c[0].length};let y=a.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(a[h]))h++;if(h>=g)break;if(a[h]!=="<"||a[h+1]==="/")break;let S=a.slice(h).match(/^<(\w+)/);if(!S)break;let C=S[1],P=r(a,h);if(P.value===void 0){h++;continue}if(C==="member"||f[C]!==void 0){if(!Array.isArray(f[C]))f[C]=f[C]!==void 0?[f[C]]:[];f[C].push(P.value)}else f[C]=P.value;h=P.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((a)=>({StackName:a.StackName||"",StackId:a.StackId,StackStatus:a.StackStatus,CreationTime:a.CreationTime,LastUpdatedTime:a.LastUpdatedTime,StackStatusReason:a.StackStatusReason,Description:a.Description}))}function Pi(e){let r=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((a)=>({StackId:a.StackId||"",EventId:a.EventId||"",StackName:a.StackName||"",LogicalResourceId:a.LogicalResourceId||"",PhysicalResourceId:a.PhysicalResourceId,ResourceType:a.ResourceType||"",Timestamp:a.Timestamp||"",ResourceStatus:a.ResourceStatus||"",ResourceStatusReason:a.ResourceStatusReason}))}var Ei=5242880,wt=5242880;var wi=5242880;class Aa{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 Fi(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(),a=this.buildUrl(e,n),s={};if(r.range)s.Range=r.range;if(r.ifModifiedSince)s["If-Modified-Since"]=r.ifModifiedSince.toUTCString();if(r.ifMatch)s["If-Match"]=r.ifMatch;if(r.ifNoneMatch)s["If-None-Match"]=r.ifNoneMatch;let c=new URL(a);if(r.responseContentType)c.searchParams.set("response-content-type",r.responseContentType);if(r.responseContentDisposition)c.searchParams.set("response-content-disposition",r.responseContentDisposition);let u=Y({method:"GET",url:c.toString(),headers:s,...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 a,s;if(typeof r==="string")a=new TextEncoder().encode(r).length,s=r;else if(r instanceof ArrayBuffer)a=r.byteLength,s=r;else if(r instanceof Uint8Array)a=r.byteLength,s=r;else if(r instanceof Blob)a=r.size,s=r;else return this.uploadMultipart(e,n,r,{...i,partSize:wt});if(a>wi){let c=Ni(s).stream();return this.uploadMultipart(e,n,c,{...i,partSize:wt})}return this.putSimple(e,n,s,a,i)}async putSimple(e,n,r,i,a){let s=await this.getCredentials(),c=this.buildUrl(e,n),u={"Content-Length":String(i),"Content-Type":a.contentType||Vn(n)};if(a.contentEncoding)u["Content-Encoding"]=a.contentEncoding;if(a.cacheControl)u["Cache-Control"]=a.cacheControl;if(a.contentDisposition)u["Content-Disposition"]=a.contentDisposition;if(a.storageClass)u["x-amz-storage-class"]=a.storageClass;if(a.serverSideEncryption)u["x-amz-server-side-encryption"]=a.serverSideEncryption;if(a.acl)u["x-amz-acl"]=a.acl;if(a.tagging)u["x-amz-tagging"]=a.tagging;if(a.metadata)for(let[y,f]of Object.entries(a.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=Y({method:"PUT",url:c,headers:u,body:d,...s,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),a=Y({method:"DELETE",url:i,...r,service:"s3",region:this.region}),s=await fetch(a.url,{method:a.method,headers:a.headers});if(!s.ok&&s.status!==204){let c=await s.text();throw new be(`Failed to delete object: ${c}`,s.status,e,n)}}async deleteMany(e,n){let r=await this.getCredentials(),i=`${this.buildUrl(e)}?delete`,s=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${n.map((h)=>`<Object><Key>${Di(h)}</Key></Object>`).join("")}</Delete>`,c=Y({method:"POST",url:i,headers:{"Content-Type":"application/xml"},body:s,...r,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:s});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 a=Y({method:"GET",url:i.toString(),...r,service:"s3",region:this.region}),s=await fetch(a.url,{method:a.method,headers:a.headers});if(!s.ok){let u=await s.text();throw new be(`Failed to list objects: ${u}`,s.status,e)}let c=await s.text();return Ii(c)}async*listAll(e,n={}){let r;do{let i=await this.list(e,{...n,continuationToken:r});for(let a of i.contents)yield a;r=i.nextContinuationToken}while(r)}async head(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),a=Y({method:"HEAD",url:i,...r,service:"s3",region:this.region}),s=await fetch(a.url,{method:a.method,headers:a.headers});if(s.status===404)return null;if(!s.ok){let u=await s.text();throw new be(`Failed to head object: ${u}`,s.status,e,n)}let c={};return s.headers.forEach((u,d)=>{if(d.toLowerCase().startsWith("x-amz-meta-"))c[d.slice(11)]=u}),{contentLength:Number(s.headers.get("Content-Length")||0),contentType:s.headers.get("Content-Type")||"application/octet-stream",etag:(s.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(s.headers.get("Last-Modified")||0),metadata:c,storageClass:s.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:s.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,a={}){let s=await this.getCredentials(),c=this.buildUrl(r,i),u={"x-amz-copy-source":`/${e}/${encodeURIComponent(n)}`};if(a.metadataDirective)u["x-amz-metadata-directive"]=a.metadataDirective;if(a.contentType)u["Content-Type"]=a.contentType;if(a.storageClass)u["x-amz-storage-class"]=a.storageClass;if(a.acl)u["x-amz-acl"]=a.acl;if(a.metadata)for(let[f,h]of Object.entries(a.metadata))u[`x-amz-meta-${f.toLowerCase()}`]=h;let d=Y({method:"PUT",url:c,headers:u,...s,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(),a=this.buildUrl(e,n);return ts({url:a,method:r.method||"GET",expiresIn:r.expiresIn||3600,...i,service:"s3",region:this.region})}async uploadMultipart(e,n,r,i={}){let a=await this.getCredentials(),s=Math.max(i.partSize||wt,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,s,a,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(),a=this.buildUrl(e,n),s=`${a}?uploads`,c={"Content-Type":r.contentType||Vn(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=Y({method:"POST",url:s,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=a;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,a,s,c,u,d,m){let p=[],g=a.getReader(),y=1,f=new Uint8Array(0),h=0,S=u?Math.ceil(u/s):void 0,C=new Map,P=async(v,I)=>{let D=`${r}?partNumber=${I}&uploadId=${encodeURIComponent(i)}`,N={"Content-Length":String(v.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},M=Y({method:"PUT",url:D,headers:N,...c,service:"s3",region:this.region}),F=await fetch(M.url,{method:M.method,headers:M.headers,body:v,redirect:"error"});if(!F.ok){let G=await F.text();throw new be(`Failed to upload part ${I}: ${G}`,F.status,e,n)}let O=(F.headers.get("ETag")||"").replace(/"/g,"");if(!O)throw new be(`Missing ETag for part ${I}`,F.status,e,n);return{partNumber:I,etag:O}},E=async()=>{let v=await Promise.race(C.values());C.delete(v.partNumber),p.push(v)};while(!0){let{done:v,value:I}=await g.read();if(I){let D=new Uint8Array(f.length+I.length);D.set(f),D.set(I,f.length),f=D}while(f.length>=s||v&&f.length>0){let D=f.slice(0,s);f=f.slice(s);let N=y++;if(C.size>=d)await E();if(C.set(N,P(D,N)),h+=D.byteLength,m)m({loaded:h,total:u||h,part:N,totalParts:S||N})}if(v)break}while(C.size>0)await E();return p.sort((v,I)=>v.partNumber-I.partNumber),p}async completeMultipartUpload(e,n,r,i,a){let s=await this.getCredentials(),c=`${r}?uploadId=${encodeURIComponent(i)}`,d=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${a.map((h)=>`<Part><PartNumber>${h.partNumber}</PartNumber><ETag>"${h.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,m=Y({method:"POST",url:c,headers:{"Content-Type":"application/xml"},body:d,...s,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 a=await this.getCredentials(),s=`${i??this.buildUrl(e,n)}?uploadId=${encodeURIComponent(r)}`,c=Y({method:"DELETE",url:s,...a,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(),a=this.buildUrl(e),s=Y({method:"DELETE",url:a,...i,service:"s3",region:this.region});await fetch(s.url,{method:s.method,headers:s.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,a;while((a=i.exec(e))!==null){let c=a[1];n.push({key:z(c,"Key")||"",lastModified:new Date(z(c,"LastModified")||0),etag:(z(c,"ETag")||"").replace(/"/g,""),size:Number(z(c,"Size")||0),storageClass:z(c,"StorageClass")||"STANDARD"})}let s=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((a=s.exec(e))!==null)r.push(a[1]);return{contents:n,commonPrefixes:r,isTruncated:z(e,"IsTruncated")==="true",continuationToken:z(e,"ContinuationToken")||void 0,nextContinuationToken:z(e,"NextContinuationToken")||void 0,keyCount:Number(z(e,"KeyCount")||0),maxKeys:Number(z(e,"MaxKeys")||1000),prefix:z(e,"Prefix")||void 0,delimiter:z(e,"Delimiter")||void 0}}function z(e,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 Vn(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 wu(e){return new Aa(e)}class Au{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await An(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 Bm(e){let{name:n,slug:r,domain:i,repository:a,phpVersion:s="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:[s],default:s},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:u,username:u,password:d}},sites:{main:{root:".",type:"laravel",domain:i,phpVersion:s,repository:{...a,strategy:p},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:m}}}}}function jm(e){let{name:n,slug:r,domain:i,layers:a,phpVersion:s="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:s,architecture:c,layers:a,memory:u,build:d,deploy:m,assets:"public",queues:!0,scheduler:g,cache:{driver:p},domain:i}}}}}function Vm(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 du=sa,uu="./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 pu=20000,mu=12000;function gu(e){return pu+Ai(e)%mu}function Bn(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 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 a of Object.values(e.sites??{})){let s=a;if(!s||s.redirect)continue;let c=s.domain;if(typeof c==="string")r.push(c);else if(Array.isArray(c))r.push(...c.filter((u)=>typeof u==="string"))}return r.filter((a)=>a&&!a.startsWith("dashboard."))}function fu(e,n,r){if(r)return r;let i=Fn(e,n),a=i[0];if(!a)return null;return Bn(a,i)}function hu(e,n,r){if(r)return[r];let i=Fn(e,n),a=[];for(let s of i){let c=Bn(s,i);if(!a.includes(c))a.push(c)}return a}function Jt(e){return Object.entries(e.sites??{}).some(([n,r])=>{if(!r)return!1;let i=r.root??"";return Br(n)||i==="ui/dist"||i.endsWith("/ui/dist")||i.endsWith("/dist/ui")})}var dl="dashboard-";function ul(e){return dl+e.replace(/^dashboard\./,"").replace(/\./g,"-")}function Br(e){return e==="dashboard"||e.startsWith(dl)}function ji(e,n,r){if(Jt(e))return[];if(e.cloud?.attachTo)return[];let i=r.password?{auth:{username:r.username||"admin",password:r.password,realm:r.realm}}:{},a=r.build===!1||r.build===void 0?{}:{build:r.build};if(r.live!==!1){let c=fu(e,n,r.domain);if(!c)return[];let u=r.port??gu(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 ${uu} --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:[du],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:ul(c),site:m}]}return hu(e,n,r.domain).map((c)=>({name:ul(c),site:{root:r.uiRoot,deploy:"server",type:"static",domain:c,ssl:{provider:"letsencrypt"},...a,...i}}))}function zm(e,n,r){return ji(e,n,r)[0]??null}function vt(e,n){let r={...e};for(let i in n){let a=n[i],s=r[i];if(a===void 0)continue;if(Array.isArray(a)&&Array.isArray(s))r[i]=[...s,...a];else if(typeof a==="object"&&a!==null&&!Array.isArray(a)&&typeof s==="object"&&s!==null&&!Array.isArray(s))r[i]=vt(s,a);else r[i]=a}return r}function pl(e,n){return vt(e,n)}function Hm(...e){return e.reduce((n,r)=>vt(n,r),{})}function qm(e,n){return(r)=>{let i=e(r);if(typeof n==="function")return pl(i,n(i,r));return pl(i,n)}}function An(e){return{infrastructure:e}}function Gm(e){return An({monitoring:e})}function Wm(e){return An({security:e})}function Km(e){return An({databases:e})}function Jm(e){return An({cache:e})}function Xm(e){return An({cdn:e})}function Qm(e){return An({queues:e})}import{existsSync as Gn,readFileSync as Tt}from"node:fs";import{homedir as _n}from"node:os";import{join as Wn}from"node:path";function yu(){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 bu(e){let n=e?.profile||process.env.AWS_PROFILE||"default",r=e?.credentialsFile||Wn(_n(),".aws","credentials");if(!Gn(r))return null;try{let i=Tt(r,"utf-8");return Ci(i,n)}catch{return null}}function Ci(e,n){let r=e.split(`
|
|
2459
|
+
`),i=null,a,s,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&&a&&s)return{accessKeyId:a,secretAccessKey:s,sessionToken:c};i=m[1],a=void 0,s=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":a=y;break;case"aws_secret_access_key":s=y;break;case"aws_session_token":c=y;break}}}if(i===n&&a&&s)return{accessKeyId:a,secretAccessKey:s,sessionToken:c};return null}async function Su(e){let n=e?.timeout??1000,r="http://169.254.169.254";try{let i=await Ke("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 a=await i.text(),s=await Ke("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":a}},n);if(!s.ok)return null;let c=(await s.text()).trim(),u=await Ke(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${c}`,{headers:{"X-aws-ec2-metadata-token":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 vu(e){let n=e?.timeout??1000,r=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,i=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,a=null;if(r)a=`http://169.254.170.2${r}`;else if(i)a=i;if(!a)return null;try{let s={},c=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(c)s.Authorization=c;let u=await Ke(a,{headers: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 Cu(e){let n=e?.timeout??5000,r=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,i=process.env.AWS_ROLE_ARN,a=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!r||!i)return null;try{let s=Tt(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:a,WebIdentityToken:s}),m=await Ke(`${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 Vi(e){let n=yu();if(n)return n;let r=bu(e);if(r)return r;let i=await Cu(e);if(i)return i;let a=await vu(e);if(a)return a;let s=await Su(e);if(s)return s;throw Error("Could not find AWS credentials. Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, or configure ~/.aws/credentials, or run on an EC2 instance with an IAM role.")}function Ym(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=Vi(e).then((i)=>(n=i,r=null,i)).catch((i)=>{throw r=null,i}),r}}async function Ke(e,n,r){let i=new AbortController,a=setTimeout(()=>i.abort(),r);try{let s=await fetch(e,{...n,signal:i.signal});return clearTimeout(a),s}catch(s){throw clearTimeout(a),s}}function Ue(e,n){let r=new RegExp(`<${n}>([^<]+)</${n}>`),i=e.match(r);return i?i[1]:null}async function Rn(e){return Vi({profile:e})}function Tu(e){let n=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(n)return n;let r=Wn(_n(),".aws","config");if(Gn(r))try{let i=Tt(r,"utf-8"),a=e||process.env.AWS_PROFILE||"default",s=a==="default"?"[default]":`[profile ${a}]`,c=i.split(`
|
|
2460
|
+
`),u=!1;for(let d of c){let m=d.trim();if(m.startsWith("[")){u=m===s;continue}if(u&&m.startsWith("region")){let[,p]=m.split("=");if(p)return p.trim()}}}catch{}return"us-east-1"}async function ml(e){let n=e||await Vi(),r=Tu(),{signRequest:i}=await import("./chunk-hzc049ns.js"),a=r.startsWith("us-gov")?`https://sts.${r}.amazonaws.com`:r==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${r}.amazonaws.com`,s="Action=GetCallerIdentity&Version=2011-06-15",c=i({method:"POST",url:a,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 Eu{profile;credentials=null;region;constructor(e="us-east-1",n="default"){this.profile=n;this.region=e}async init(){if(this.credentials=await Rn(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",...Et(n)},a=new URLSearchParams(i).toString(),c=await(await kt({method:"POST",url:`https://cloudformation.${this.region}.amazonaws.com/`,service:"cloudformation",region:this.region,headers:{"Content-Type":"application/x-www-form-urlencoded"},body:a,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[a,[s,c]]of Object.entries(e.parameters).entries())n[`Parameters.member.${a+1}.ParameterKey`]=s,n[`Parameters.member.${a+1}.ParameterValue`]=c;if(e.capabilities)for(let[a,s]of e.capabilities.entries())n[`Capabilities.member.${a+1}`]=s;if(e.tags)for(let[a,[s,c]]of Object.entries(e.tags).entries())n[`Tags.member.${a+1}.Key`]=s,n[`Tags.member.${a+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[a,[s,c]]of Object.entries(e.parameters).entries())n[`Parameters.member.${a+1}.ParameterKey`]=s,n[`Parameters.member.${a+1}.ParameterValue`]=c;if(e.capabilities)for(let[a,s]of e.capabilities.entries())n[`Capabilities.member.${a+1}`]=s;if(e.tags)for(let[a,[s,c]]of Object.entries(e.tags).entries())n[`Tags.member.${a+1}.Key`]=s,n[`Tags.member.${a+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,a=Array.isArray(i)?i[0]:i;if(!a)throw Error(`Stack ${e} not found`);return Ti(a)}async listStacks(e){let n={};if(e)for(let[i,a]of e.entries())n[`StackStatusFilter.member.${i+1}`]=a;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 s=0,c=null;while(s<360){s++;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 a={"stack-create-complete":["CREATE_COMPLETE"],"stack-update-complete":["UPDATE_COMPLETE"],"stack-delete-complete":["DELETE_COMPLETE"]}[n];if(!a)throw Error(`Unknown waiter: ${n}`);return this.waitForStack(e,a,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,[a,s]]of Object.entries(e.parameters).entries())n[`Parameters.member.${i+1}.ParameterKey`]=a,n[`Parameters.member.${i+1}.ParameterValue`]=s;if(e.capabilities)for(let[i,a]of e.capabilities.entries())n[`Capabilities.member.${i+1}`]=a;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,a=Array.isArray(i)?i[0]:i;if(!a)return{};let s={},c=a.Outputs?.member;if(c){let u=Array.isArray(c)?c:[c];for(let d of u)if(d.OutputKey&&d.OutputValue)s[d.OutputKey]=d.OutputValue}return s}}function Et(e,n=""){let r={};for(let[i,a]of Object.entries(e)){let s=n?`${n}.${i}`:i;if(Array.isArray(a))a.forEach((c,u)=>{if(typeof c==="object")Object.assign(r,Et(c,`${s}.${u+1}`));else r[`${s}.${u+1}`]=String(c)});else if(typeof a==="object"&&a!==null)Object.assign(r,Et(a,s));else if(a!==void 0&&a!==null)r[s]=String(a)}return r}function vi(e){e=e.replace(/<\?xml[^?]*\?>\s*/,"").trim();function n(a,s,c){let u=1,d=c,m=`<${s}`,p=`</${s}>`;while(d<a.length&&u>0){let g=a.indexOf(m,d),y=a.indexOf(p,d);if(y===-1)return-1;if(g!==-1&&g<y){let f=a[g+m.length];if(f===">"||f===" "||f==="/"){let h=a.indexOf(">",g);if(h!==-1&&a[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(a,s){while(s<a.length&&/\s/.test(a[s]))s++;if(s>=a.length||a[s]!=="<"){let S=a.indexOf("<",s);if(S===-1)return{value:a.slice(s).trim(),end:a.length};return{value:a.slice(s,S).trim(),end:S}}if(a[s+1]==="/")return{value:void 0,end:s};let c=a.slice(s).match(/^<(\w+)([^>]*?)\/?>/);if(!c)return{value:void 0,end:s+1};let u=c[1];if(c[0].endsWith("/>"))return{value:"",end:s+c[0].length};let m=s+c[0].length,p=`</${u}>`,g=n(a,u,m);if(g===-1)return{value:void 0,end:s+c[0].length};let y=a.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(a[h]))h++;if(h>=g)break;if(a[h]!=="<"||a[h+1]==="/")break;let S=a.slice(h).match(/^<(\w+)/);if(!S)break;let C=S[1],P=r(a,h);if(P.value===void 0){h++;continue}if(C==="member"||f[C]!==void 0){if(!Array.isArray(f[C]))f[C]=f[C]!==void 0?[f[C]]:[];f[C].push(P.value)}else f[C]=P.value;h=P.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((a)=>({StackName:a.StackName||"",StackId:a.StackId,StackStatus:a.StackStatus,CreationTime:a.CreationTime,LastUpdatedTime:a.LastUpdatedTime,StackStatusReason:a.StackStatusReason,Description:a.Description}))}function Pi(e){let r=(e?.DescribeStackEventsResult||e?.DescribeStackEventsResponse?.DescribeStackEventsResult||e)?.StackEvents?.member;if(!r)return[];return(Array.isArray(r)?r:[r]).map((a)=>({StackId:a.StackId||"",EventId:a.EventId||"",StackName:a.StackName||"",LogicalResourceId:a.LogicalResourceId||"",PhysicalResourceId:a.PhysicalResourceId,ResourceType:a.ResourceType||"",Timestamp:a.Timestamp||"",ResourceStatus:a.ResourceStatus||"",ResourceStatusReason:a.ResourceStatusReason}))}var Ei=5242880,wt=5242880;var wi=5242880;class Aa{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 Vi(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(),a=this.buildUrl(e,n),s={};if(r.range)s.Range=r.range;if(r.ifModifiedSince)s["If-Modified-Since"]=r.ifModifiedSince.toUTCString();if(r.ifMatch)s["If-Match"]=r.ifMatch;if(r.ifNoneMatch)s["If-None-Match"]=r.ifNoneMatch;let c=new URL(a);if(r.responseContentType)c.searchParams.set("response-content-type",r.responseContentType);if(r.responseContentDisposition)c.searchParams.set("response-content-disposition",r.responseContentDisposition);let u=Y({method:"GET",url:c.toString(),headers:s,...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 a,s;if(typeof r==="string")a=new TextEncoder().encode(r).length,s=r;else if(r instanceof ArrayBuffer)a=r.byteLength,s=r;else if(r instanceof Uint8Array)a=r.byteLength,s=r;else if(r instanceof Blob)a=r.size,s=r;else return this.uploadMultipart(e,n,r,{...i,partSize:wt});if(a>wi){let c=Ni(s).stream();return this.uploadMultipart(e,n,c,{...i,partSize:wt})}return this.putSimple(e,n,s,a,i)}async putSimple(e,n,r,i,a){let s=await this.getCredentials(),c=this.buildUrl(e,n),u={"Content-Length":String(i),"Content-Type":a.contentType||Vn(n)};if(a.contentEncoding)u["Content-Encoding"]=a.contentEncoding;if(a.cacheControl)u["Cache-Control"]=a.cacheControl;if(a.contentDisposition)u["Content-Disposition"]=a.contentDisposition;if(a.storageClass)u["x-amz-storage-class"]=a.storageClass;if(a.serverSideEncryption)u["x-amz-server-side-encryption"]=a.serverSideEncryption;if(a.acl)u["x-amz-acl"]=a.acl;if(a.tagging)u["x-amz-tagging"]=a.tagging;if(a.metadata)for(let[y,f]of Object.entries(a.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=Y({method:"PUT",url:c,headers:u,body:d,...s,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),a=Y({method:"DELETE",url:i,...r,service:"s3",region:this.region}),s=await fetch(a.url,{method:a.method,headers:a.headers});if(!s.ok&&s.status!==204){let c=await s.text();throw new be(`Failed to delete object: ${c}`,s.status,e,n)}}async deleteMany(e,n){let r=await this.getCredentials(),i=`${this.buildUrl(e)}?delete`,s=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${n.map((h)=>`<Object><Key>${Di(h)}</Key></Object>`).join("")}</Delete>`,c=Y({method:"POST",url:i,headers:{"Content-Type":"application/xml"},body:s,...r,service:"s3",region:this.region}),u=await fetch(c.url,{method:c.method,headers:c.headers,body:s});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 a=Y({method:"GET",url:i.toString(),...r,service:"s3",region:this.region}),s=await fetch(a.url,{method:a.method,headers:a.headers});if(!s.ok){let u=await s.text();throw new be(`Failed to list objects: ${u}`,s.status,e)}let c=await s.text();return Ii(c)}async*listAll(e,n={}){let r;do{let i=await this.list(e,{...n,continuationToken:r});for(let a of i.contents)yield a;r=i.nextContinuationToken}while(r)}async head(e,n){let r=await this.getCredentials(),i=this.buildUrl(e,n),a=Y({method:"HEAD",url:i,...r,service:"s3",region:this.region}),s=await fetch(a.url,{method:a.method,headers:a.headers});if(s.status===404)return null;if(!s.ok){let u=await s.text();throw new be(`Failed to head object: ${u}`,s.status,e,n)}let c={};return s.headers.forEach((u,d)=>{if(d.toLowerCase().startsWith("x-amz-meta-"))c[d.slice(11)]=u}),{contentLength:Number(s.headers.get("Content-Length")||0),contentType:s.headers.get("Content-Type")||"application/octet-stream",etag:(s.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(s.headers.get("Last-Modified")||0),metadata:c,storageClass:s.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:s.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,a={}){let s=await this.getCredentials(),c=this.buildUrl(r,i),u={"x-amz-copy-source":`/${e}/${encodeURIComponent(n)}`};if(a.metadataDirective)u["x-amz-metadata-directive"]=a.metadataDirective;if(a.contentType)u["Content-Type"]=a.contentType;if(a.storageClass)u["x-amz-storage-class"]=a.storageClass;if(a.acl)u["x-amz-acl"]=a.acl;if(a.metadata)for(let[f,h]of Object.entries(a.metadata))u[`x-amz-meta-${f.toLowerCase()}`]=h;let d=Y({method:"PUT",url:c,headers:u,...s,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(),a=this.buildUrl(e,n);return is({url:a,method:r.method||"GET",expiresIn:r.expiresIn||3600,...i,service:"s3",region:this.region})}async uploadMultipart(e,n,r,i={}){let a=await this.getCredentials(),s=Math.max(i.partSize||wt,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,s,a,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(),a=this.buildUrl(e,n),s=`${a}?uploads`,c={"Content-Type":r.contentType||Vn(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=Y({method:"POST",url:s,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=a;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,a,s,c,u,d,m){let p=[],g=a.getReader(),y=1,f=new Uint8Array(0),h=0,S=u?Math.ceil(u/s):void 0,C=new Map,P=async(v,I)=>{let D=`${r}?partNumber=${I}&uploadId=${encodeURIComponent(i)}`,N={"Content-Length":String(v.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},M=Y({method:"PUT",url:D,headers:N,...c,service:"s3",region:this.region}),F=await fetch(M.url,{method:M.method,headers:M.headers,body:v,redirect:"error"});if(!F.ok){let G=await F.text();throw new be(`Failed to upload part ${I}: ${G}`,F.status,e,n)}let O=(F.headers.get("ETag")||"").replace(/"/g,"");if(!O)throw new be(`Missing ETag for part ${I}`,F.status,e,n);return{partNumber:I,etag:O}},E=async()=>{let v=await Promise.race(C.values());C.delete(v.partNumber),p.push(v)};while(!0){let{done:v,value:I}=await g.read();if(I){let D=new Uint8Array(f.length+I.length);D.set(f),D.set(I,f.length),f=D}while(f.length>=s||v&&f.length>0){let D=f.slice(0,s);f=f.slice(s);let N=y++;if(C.size>=d)await E();if(C.set(N,P(D,N)),h+=D.byteLength,m)m({loaded:h,total:u||h,part:N,totalParts:S||N})}if(v)break}while(C.size>0)await E();return p.sort((v,I)=>v.partNumber-I.partNumber),p}async completeMultipartUpload(e,n,r,i,a){let s=await this.getCredentials(),c=`${r}?uploadId=${encodeURIComponent(i)}`,d=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${a.map((h)=>`<Part><PartNumber>${h.partNumber}</PartNumber><ETag>"${h.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,m=Y({method:"POST",url:c,headers:{"Content-Type":"application/xml"},body:d,...s,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 a=await this.getCredentials(),s=`${i??this.buildUrl(e,n)}?uploadId=${encodeURIComponent(r)}`,c=Y({method:"DELETE",url:s,...a,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(),a=this.buildUrl(e),s=Y({method:"DELETE",url:a,...i,service:"s3",region:this.region});await fetch(s.url,{method:s.method,headers:s.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,a;while((a=i.exec(e))!==null){let c=a[1];n.push({key:z(c,"Key")||"",lastModified:new Date(z(c,"LastModified")||0),etag:(z(c,"ETag")||"").replace(/"/g,""),size:Number(z(c,"Size")||0),storageClass:z(c,"StorageClass")||"STANDARD"})}let s=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((a=s.exec(e))!==null)r.push(a[1]);return{contents:n,commonPrefixes:r,isTruncated:z(e,"IsTruncated")==="true",continuationToken:z(e,"ContinuationToken")||void 0,nextContinuationToken:z(e,"NextContinuationToken")||void 0,keyCount:Number(z(e,"KeyCount")||0),maxKeys:Number(z(e,"MaxKeys")||1000),prefix:z(e,"Prefix")||void 0,delimiter:z(e,"Delimiter")||void 0}}function z(e,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 Vn(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 wu(e){return new Aa(e)}class Au{profile;credentials=null;constructor(e="default"){this.profile=e}async init(){this.credentials=await Rn(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
2462
|
<InvalidationBatch>
|
|
2463
2463
|
<Paths>
|
|
2464
2464
|
<Quantity>${e.paths.length}</Quantity>
|
|
@@ -2467,24 +2467,24 @@ Reason: ${u.StackStatusReason||"Unknown"}`);await new Promise((d)=>setTimeout(d,
|
|
|
2467
2467
|
</Items>
|
|
2468
2468
|
</Paths>
|
|
2469
2469
|
<CallerReference>${r}</CallerReference>
|
|
2470
|
-
</InvalidationBatch>`,a=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e.distributionId}/invalidation`,s=await kt({method:"POST",url:a,service:"cloudfront",region:"us-east-1",headers:{"Content-Type":"text/xml"},body:i,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,sessionToken:n.sessionToken});return(await
|
|
2470
|
+
</InvalidationBatch>`,a=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e.distributionId}/invalidation`,s=await kt({method:"POST",url:a,service:"cloudfront",region:"us-east-1",headers:{"Content-Type":"text/xml"},body:i,accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,sessionToken:n.sessionToken});return(await Dn(s)).Id}async getInvalidation(e,n){let r=await this.ensureCredentials(),i=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e}/invalidation/${n}`,a=await kt({method:"GET",url:i,service:"cloudfront",region:"us-east-1",accessKeyId:r.accessKeyId,secretAccessKey:r.secretAccessKey,sessionToken:r.sessionToken});return await Dn(a)}async listInvalidations(e){let n=await this.ensureCredentials(),r=`https://cloudfront.amazonaws.com/2020-05-31/distribution/${e}/invalidation`,i=await kt({method:"GET",url:r,service:"cloudfront",region:"us-east-1",accessKeyId:n.accessKeyId,secretAccessKey:n.secretAccessKey,sessionToken:n.sessionToken});return(await Dn(i)).Items||[]}async waitForInvalidation(e,n,r=60,i=5000){for(let a=0;a<r;a++){if((await this.getInvalidation(e,n)).Status==="Completed")return;if(a<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 Pt 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,Pt)}toString(){let e=`${this.name} [${this.code}]: ${this.message}`;if(this.solution)e+=`
|
|
2471
2471
|
|
|
2472
2472
|
\uD83D\uDCA1 Solution: ${this.solution}`;if(this.details&&Object.keys(this.details).length>0){e+=`
|
|
2473
2473
|
|
|
2474
2474
|
Details:`;for(let[n,r]of Object.entries(this.details))e+=`
|
|
2475
|
-
${n}: ${JSON.stringify(r)}`}return e}}class
|
|
2475
|
+
${n}: ${JSON.stringify(r)}`}return e}}class Zo extends Pt{constructor(e,n,r){super(e,"CONFIG_ERROR",n,r);this.name="ConfigurationError"}}class Xt extends Pt{constructor(e,n,r){super(e,"CREDENTIAL_ERROR",n,r);this.name="CredentialError"}}class Ru extends Pt{constructor(e,n,r){super(e,"DEPLOYMENT_ERROR",n,r);this.name="DeploymentError"}}class gl extends Pt{constructor(e,n,r){super(e,"VALIDATION_ERROR",n,r);this.name="ValidationError"}}class Iu extends Pt{statusCode;constructor(e,n,r,i){super(e,"AWS_API_ERROR",r,i);this.statusCode=n;this.name="AWSAPIError"}}var Pu={NO_CREDENTIALS:{message:"AWS credentials not found",solution:`Configure AWS credentials using one of these methods:
|
|
2476
2476
|
1. Set environment variables: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
|
|
2477
2477
|
2. Create ~/.aws/credentials file with your credentials
|
|
2478
2478
|
3. Use an IAM role (for EC2 instances)
|
|
2479
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 Du(e){return Pu[e]}function fl(e,n){let r=Du(e);return new Pt(r.message,e,r.solution,n)}class Se{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 Pt)console.error(n.toString());else console.error(n.message);if(this.debugMode&&n.stack)console.error(`
|
|
2480
|
-
Stack trace:`),console.error(n.stack)}}static success(e){console.log(`✔ ${e}`)}}function Zm(e){if(!e)throw fl("MISSING_CONFIG");if(!e.project)throw new
|
|
2480
|
+
Stack trace:`),console.error(n.stack)}}static success(e){console.log(`✔ ${e}`)}}function Zm(e){if(!e)throw fl("MISSING_CONFIG");if(!e.project)throw new Zo("Missing required field: project","Add a project configuration with name, slug, and region",{field:"project"});if(!e.project.name)throw new Zo("Missing required field: project.name","Add a project name to your configuration",{field:"project.name"});if(!e.project.slug)throw new Zo("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 gl("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 fl("INVALID_REGION",{region:e.project.region})}Se.success("Configuration validation passed")}function eg(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 tg(e="default"){try{Se.verbose("Resolving AWS credentials...");let n=await Rn(e);if(!n.accessKeyId||!n.secretAccessKey)throw new Xt("AWS credentials are incomplete","Ensure both AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are set");Se.verbose("Credentials resolved successfully"),Se.debug("Access Key ID:",n.accessKeyId.substring(0,8)+"..."),Se.verbose("Testing credentials with GetCallerIdentity...");let r;try{r=await ml(n),Se.verbose("Credentials are valid"),Se.debug("Account ID:",r)}catch(i){if(i instanceof Error)if(i.message.includes("InvalidClientTokenId"))throw new Xt("Invalid AWS access key ID","Check that your AWS_ACCESS_KEY_ID is correct");else if(i.message.includes("SignatureDoesNotMatch"))throw new Xt("Invalid AWS secret access key","Check that your AWS_SECRET_ACCESS_KEY is correct");else if(i.message.includes("ExpiredToken"))throw new Xt("AWS credentials have expired","Refresh your temporary credentials or use long-term credentials");else throw new Xt(`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 Xt)throw n;return{valid:!1,error:n instanceof Error?n.message:"Unknown error"}}}async function rg(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 ng(e){let n=ku(e);return JSON.stringify({Version:"2012-10-17",Statement:[{Effect:"Allow",Action:n,Resource:"*"}]},null,2)}var Ne={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 ig(e){let n=[];if(Se.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:Ne.ec2["Running On-Demand Instances"],percentage:i/Ne.ec2["Running On-Demand Instances"]*100,warning:i>Ne.ec2["Running On-Demand Instances"]*0.8})}if(e.infrastructure?.network?.vpc)n.push({service:"EC2",quotaName:"VPCs",currentValue:1,limit:Ne.ec2.VPCs,percentage:1/Ne.ec2.VPCs*100,warning:!1});if(e.infrastructure?.database?.postgres||e.infrastructure?.database?.mysql)n.push({service:"RDS",quotaName:"DB Instances",currentValue:1,limit:Ne.rds["DB Instances"],percentage:1/Ne.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:Ne.s3.Buckets,percentage:i/Ne.s3.Buckets*100,warning:i>Ne.s3.Buckets*0.8})}if(e.infrastructure?.functions){let i=0;for(let a of Object.values(e.infrastructure.functions))if(Array.isArray(a))i+=a.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:Ne.dynamodb.Tables,percentage:i/Ne.dynamodb.Tables*100,warning:i>Ne.dynamodb.Tables*0.8})}let r=n.filter((i)=>i.warning);if(r.length>0){Se.warn("Service quota warnings detected:");for(let i of r)Se.warn(` ${i.service} - ${i.quotaName}: ${i.currentValue}/${i.limit} (${i.percentage.toFixed(1)}%)`)}else Se.verbose("All service quotas are within limits");return n}function og(e){if(e.length===0)return"No quotas to check";let n=`Service Quota Usage:
|
|
2481
2481
|
|
|
2482
2482
|
`,r=e.reduce((i,a)=>{if(!i[a.service])i[a.service]=[];return i[a.service].push(a),i},{});for(let[i,a]of Object.entries(r)){n+=`${i}:
|
|
2483
2483
|
`;for(let s of a){let c=s.warning?"⚠":"✓";n+=` ${c} ${s.quotaName}: ${s.currentValue}/${s.limit} (${s.percentage.toFixed(1)}%)
|
|
2484
2484
|
`}n+=`
|
|
2485
|
-
`}return n}function sg(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 jn}from"node:crypto";import{existsSync as
|
|
2486
|
-
`);return yl(r)}function dg(e){let n=
|
|
2487
|
-
`)}function vg(e,n,r){if(e.deleted.length>0)return!0;for(let i of e.modified){let a=n.Resources[i],s=r.Resources[i];if(a.Type!==s.Type)return!0;let c=qi(s.Type);for(let u of c){let d=a.Properties?.[u],m=s.Properties?.[u];if(JSON.stringify(d)!==JSON.stringify(m))return!0}}return!1}function qi(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 Cg(e){let n=[],r=[],i=[];n.push(...e.added);for(let a of e.modified)r.push(a);return i.push(...e.deleted),{safe:n,caution:r,dangerous:i}}function Tg(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 Eg(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 $u={$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 wg(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 bl={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 Da(){return bl}function Ag(){return bl.enabled}function Rg(e){let n=Da();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 Ig(){let e=Da();return{accessKeyId:e.awsAccessKeyId,secretAccessKey:e.awsSecretAccessKey,region:e.awsRegion}}function Pg(){let e=Da();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 Sl{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 vl{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 Cl{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 Dg(e){return{cloudformation:new Sl,s3:new vl,dynamodb:new Cl}}class ka{environments=new Map;async createPreviewEnvironment(e){let{branch:n,pr:r,commitSha:i,ttl:a=24,baseConfig:s,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()+a*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(s,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,a=[],s=[],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)a.push(m.id);else try{await this.destroyPreviewEnvironment(m.id),a.push(m.id)}catch(g){s.push(m.id)}}return{destroyed:a,failed:s}}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(),a=r?.substring(0,7)||Date.now().toString();return n?`pr-${n}-${a}`:`${i}-${a}`}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 Lu=new ka;function Mu(e={}){let{workflowName:n="Preview Environment",trigger:r="pull_request",branches:i=["main","develop"],awsRegion:a="us-east-1",awsRole:s,configFile:c="cloud.config.ts",ttl:u=24}=e;return`name: ${n}
|
|
2485
|
+
`}return n}function sg(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 jn}from"node:crypto";import{existsSync as nt,mkdirSync as xi,readdirSync as Un,readFileSync as Hn,unlinkSync as qe,writeFileSync as ki}from"node:fs";import{join as Nt}from"node:path";class Ra{cacheDir;ttl;constructor(e,n={}){this.cacheDir=e,this.ttl=n.ttl||86400000}ensureCacheDir(){if(!nt(this.cacheDir))xi(this.cacheDir,{recursive:!0})}getCachePath(e){let n=jn("sha256").update(e).digest("hex");return Nt(this.cacheDir,`${n}.json`)}get(e){let n=this.getCachePath(e);if(!nt(n))return;try{let r=Hn(n,"utf-8"),i=JSON.parse(r);if(Date.now()-i.timestamp>this.ttl){qe(n);return}return i.value}catch{qe(n);return}}set(e,n,r){this.ensureCacheDir();let i=this.getCachePath(e),a={value:n,timestamp:Date.now(),hash:r};ki(i,JSON.stringify(a),"utf-8")}has(e){return this.get(e)!==void 0}clear(){if(!nt(this.cacheDir))return;let e=Un(this.cacheDir);for(let n of e)qe(Nt(this.cacheDir,n))}prune(){if(!nt(this.cacheDir))return;let e=Un(this.cacheDir),n=Date.now();for(let r of e){let i=Nt(this.cacheDir,r);try{let a=Hn(i,"utf-8"),s=JSON.parse(a);if(n-s.timestamp>this.ttl)qe(i)}catch{qe(i)}}}}class Ia{cache;constructor(e=je("cache","templates")){this.cache=new Ra(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),a=this.hashTemplate(n);return i!==a}hashTemplate(e){return jn("sha256").update(e).digest("hex")}clear(){this.cache.clear()}prune(){this.cache.prune()}}var xt=null;function Nu(){if(!xt)xt=new Ia;return xt}import{createHash as Mt}from"node:crypto";import{createReadStream as Oi,readdirSync as $i,statSync as rt}from"node:fs";import{join as _i,relative as Wi}from"node:path";async function hl(e,n={}){let r=n.algorithm||"sha256",i=n.chunkSize||65536;return new Promise((a,s)=>{let c=Mt(r),u=Oi(e,{highWaterMark:i});u.on("data",(d)=>c.update(d)),u.on("end",()=>a(c.digest("hex"))),u.on("error",s)})}function yl(e,n="sha256"){return Mt(n).update(e).digest("hex")}function ag(e,n="sha256"){return Mt(n).update(e).digest("hex")}async function cg(e,n={}){let r=n.ignorePatterns||["node_modules",".git","dist","build",Cn()],i=[];async function a(s){let c=$i(s,{withFileTypes:!0});for(let u of c){let d=_i(s,u.name),m=Wi(e,d);if(r.some((p)=>m.includes(p)))continue;if(u.isDirectory())await a(d);else if(u.isFile()){let p=rt(d),g=await hl(d,n);i.push({path:m,hash:g,size:p.size,mtime:p.mtimeMs})}}}return await a(e),i}function lg(e){let r=[...e].sort((i,a)=>i.path.localeCompare(a.path)).map((i)=>`${i.path}:${i.hash}`).join(`
|
|
2486
|
+
`);return yl(r)}function dg(e){let n=rt(e);return yl(`${e}:${n.size}:${n.mtimeMs}`)}function ug(e,n){let r=new Map(e.map((u)=>[u.path,u])),i=new Map(n.map((u)=>[u.path,u])),a=[],s=[],c=[];for(let[u,d]of i){let m=r.get(u);if(!m)a.push(d);else if(m.hash!==d.hash)s.push(d)}for(let[u,d]of r)if(!i.has(u))c.push(d);return{added:a,modified:s,deleted:c}}class xu{cache;constructor(){this.cache=new Map}get(e){let n=rt(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=rt(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 hl(e,n);return this.set(e,i),i}clear(){this.cache.clear()}}async function Pa(e,n={}){let r=n.concurrency||5,i=n.stopOnError??!0,a=[],s=[],c=Date.now(),u=[...e],d=[];async function m(y,f){try{let h=await y();a[f]=h}catch(h){let S=h instanceof Error?h:Error(String(h));if(s.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&&s.length>0)break}let g=Date.now()-c;return{results:a.filter((y)=>y!==void 0),errors:s,duration:g}}async function pg(e,n,r={}){let i=e.map((a)=>()=>n(a));return Pa(i,r)}async function mg(e,n,r=5){let i=e.map((s,c)=>()=>n(s,c)),a=await Pa(i,{concurrency:r,stopOnError:!1});if(a.errors.length>0)throw AggregateError(a.errors,"Parallel map failed");return a.results}async function gg(e,n={}){let r=n.retries||3,i=n.retryDelay||1000,a=e.map((s)=>async()=>{let c;for(let u=0;u<=r;u++)try{return await s()}catch(d){if(c=d instanceof Error?d:Error(String(d)),u<r)await Kn(i*(u+1))}throw c});return Pa(a,n)}async function fg(e){let n=[];for(let r of e){let i=await r();n.push(i)}return n}function Kn(e){return new Promise((n)=>setTimeout(n,e))}async function hg(e,n,r="Operation timed out"){return Promise.race([e(),new Promise((i,a)=>setTimeout(()=>a(Error(r)),n))])}class _u{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 Kn(this.minInterval-e)}return new Promise((e)=>this.queue.push(e))}processQueue(){if(this.queue.length>0&&this.running<this.maxConcurrent)this.queue.shift()()}stats(){return{running:this.running,queued:this.queue.length}}}function Ou(e,n){let r=[];for(let i=0;i<e.length;i+=n)r.push(e.slice(i,i+n));return r}async function yg(e,n,r){let i=Ou(e,n),a=[];for(let s of i){let c=await r(s);a.push(...c)}return a}function bg(e,n){let r=[],i=[],a=[],s=[],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))a.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 s.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:a,unchanged:s,parametersChanged:p,outputsChanged:g,hasChanges:r.length>0||i.length>0||a.length>0||p||g}}function Sg(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(`
|
|
2487
|
+
`)}function vg(e,n,r){if(e.deleted.length>0)return!0;for(let i of e.modified){let a=n.Resources[i],s=r.Resources[i];if(a.Type!==s.Type)return!0;let c=Ki(s.Type);for(let u of c){let d=a.Properties?.[u],m=s.Properties?.[u];if(JSON.stringify(d)!==JSON.stringify(m))return!0}}return!1}function Ki(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 Cg(e){let n=[],r=[],i=[];n.push(...e.added);for(let a of e.modified)r.push(a);return i.push(...e.deleted),{safe:n,caution:r,dangerous:i}}function Tg(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 Eg(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 $u={$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 wg(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 bl={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 Da(){return bl}function Ag(){return bl.enabled}function Rg(e){let n=Da();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 Ig(){let e=Da();return{accessKeyId:e.awsAccessKeyId,secretAccessKey:e.awsSecretAccessKey,region:e.awsRegion}}function Pg(){let e=Da();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 Sl{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 vl{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 Cl{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 Dg(e){return{cloudformation:new Sl,s3:new vl,dynamodb:new Cl}}class ka{environments=new Map;async createPreviewEnvironment(e){let{branch:n,pr:r,commitSha:i,ttl:a=24,baseConfig:s,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()+a*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(s,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,a=[],s=[],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)a.push(m.id);else try{await this.destroyPreviewEnvironment(m.id),a.push(m.id)}catch(g){s.push(m.id)}}return{destroyed:a,failed:s}}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(),a=r?.substring(0,7)||Date.now().toString();return n?`pr-${n}-${a}`:`${i}-${a}`}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 Lu=new ka;function Mu(e={}){let{workflowName:n="Preview Environment",trigger:r="pull_request",branches:i=["main","develop"],awsRegion:a="us-east-1",awsRole:s,configFile:c="cloud.config.ts",ttl:u=24}=e;return`name: ${n}
|
|
2488
2488
|
|
|
2489
2489
|
on:
|
|
2490
2490
|
${r}:
|
|
@@ -2736,8 +2736,8 @@ ${n.map((r)=>` • ${r}`).join(`
|
|
|
2736
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 Gu{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 Wu{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 Ku{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),a=i.length>0?i.reduce((u,d)=>u+(d.duration||0),0)/i.length:0,s=this.getMostUsed(1),c=s.length>0?s[0].command:"N/A";return{total:e,successful:n,failed:r,averageDuration:a,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(`
|
|
2737
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((a)=>a.command.toLowerCase().startsWith(r)).map((a)=>a.command);return[...new Set(i)].slice(0,n)}analyzePatterns(){let e=new Map,n=new Map;for(let i of this.entries){let a=i.timestamp.getHours(),s=i.timestamp.getDay();e.set(a,(e.get(a)||0)+1),n.set(s,(n.get(s)||0)+1)}let r=this.entries.length>0?this.getSuccessful().length/this.entries.length:0;return{timeOfDay:e,dayOfWeek:n,successRate:r}}}function Gg(e,n={}){let{maxWidth:r=100}=n;if(e.length===0)return"No command history";let i=[];for(let a=0;a<e.length;a++){let s=e[a],c=(a+1).toString().padStart(4),u=s.timestamp.toLocaleString(),d=s.success?"✓":"✗",m=s.command;if(m.length>r-30)m=m.substring(0,r-33)+"...";let p=`${c} ${u} ${d} ${m}`;if(s.duration)p+=` (${s.duration}ms)`;i.push(p)}return i.join(`
|
|
2738
2738
|
`)}function Wg(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(`
|
|
2739
|
-
`)}class El{deployments=new Map;async deploy(e,n){let r=this.generateDeploymentId(),i={id:r,regions:n.regions.map((a)=>({region:a.code,stackName:this.getStackName(e,a.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(r,i);try{let a=n.regions.find((c)=>c.isPrimary)||n.regions[0];await this.deployToRegion(e,a,i);let s=n.regions.filter((c)=>c.code!==a.code);if(await Promise.all(s.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(a){throw i.status="failed",i.endTime=new Date,a}}async deployToRegion(e,n,r){let i=r.regions.find((a)=>a.region===n.code);if(!i)throw Error(`Region deployment not found: ${n.code}`);i.status="deploying",i.startTime=new Date;try{let a=this.createRegionConfig(e,n);await this.deployStack(i.stackName,a,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(a){throw i.status="failed",i.endTime=new Date,i.error=a instanceof Error?a.message:String(a),a}}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 a of e.regions){if(a.status!=="deployed")continue;let s={id:`health-${a.region}`,endpoint:a.outputs?.endpoint,path:n.failover?.healthCheckPath||"/health",region:a.region};r.push(s);let c={name:"example.com",type:"A",region:a.region,setIdentifier:a.region,healthCheckId:s.id,resourceRecords:[a.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,a)=>{let s=n.regions[a];return{id:`origin-${i.region}`,domainName:i.outputs?.endpoint,weight:s?.weight||100}}),status:"Deployed"}}async deployWAF(e){return{webAclId:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6",webAclArn:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6"}}async setupReplication(e,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],a=n[r+1];console.log(`Setting up S3 replication: ${i.region} -> ${a.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((a,s)=>n.regions[s]?.isPrimary)||e.regions[0],i=e.regions.filter((a)=>a.region!==r.region);console.log(`Setting up failover: primary=${r.region}, secondary=${i.map((a)=>a.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 Kg=new El;class wl{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((a)=>a.exportName===n)?.value}createReference(e,n,r,i){let a=`/cross-region/${e}/${r}/${i}`;return this.references.push({sourceRegion:e,targetRegion:n,resourceType:r,resourceId:i,value:a}),a}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 Al{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 Rl{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 Il{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=(a)=>{let s=`${a.name}:${a.region}`;if(n.has(s))return;n.add(s);let c=this.getDependencies(a.name,a.region);for(let u of c)i({name:u.dependsOnStack,region:u.dependsOnRegion});r.push(a)};for(let a of e)i(a);return r}detectCircularDependencies(){let e=new Set,n=new Set,r=(i,a)=>{let s=`${i}:${a}`;if(n.has(s))return!0;if(e.has(s))return!1;e.add(s),n.add(s);let c=this.getDependencies(i,a);for(let u of c)if(r(u.dependsOnStack,u.dependsOnRegion))return!0;return n.delete(s),!1};for(let i of this.dependencies)if(r(i.dependentStack,i.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var Jg=new wl,Xg=new Al,Qg=new Rl,Yg=new Il;var ot=[{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 Bi(e){return ot.find((n)=>n.code===e)}function Zg(){return ot}function ef(e){let n=e.toLowerCase();return ot.filter((r)=>r.location.toLowerCase().includes(n))}function tf(e){return ot.filter((n)=>n.compliance.includes(e))}function rf(e){return ot.filter((n)=>n.pricing.tier===e)}function nf(e){return ot.some((n)=>n.code===e)}function of(e){if(e.continent==="North America")return Bi("us-east-1");if(e.continent==="Europe")return Bi("eu-west-1");if(e.continent==="Asia")return Bi("ap-southeast-1");return Bi("us-east-1")}function sf(e){let n=[...ot];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 af(e){let n=Bi(e);if(!n)throw Error(`Invalid region: ${e}`);let r=[];for(let i of ot){if(i.code===e)continue;let a=ea(n,i),s=ta(n,i);r.push({primary:n,secondary:i,distance:a,sameContinent:s})}return r.sort((i,a)=>{if(i.sameContinent!==a.sameContinent)return i.sameContinent?1:-1;return i.distance-a.distance}),r.slice(0,3)}function ea(e,n){let r={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},i=Qe(e.location),a=Qe(n.location);return Math.abs((r[i]||0)-(r[a]||0))}function ta(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 Ju(e){return`${e.name} (${e.code})`}function cf(e){return e.map((n)=>Ju(n)).join(`
|
|
2740
|
-
`)}function lf(){let e={total:ot.length,byContinent:{},byPricingTier:{}};for(let n of ot){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 Pl{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,a){let s={roleArn:`arn:aws:iam::${n}:role/${r}`,roleName:r,sourceAccountId:e,targetAccountId:n,permissions:i,externalId:a?.externalId,sessionDuration:a?.sessionDuration||3600};return this.crossAccountRoles.push(s),s}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 Dl{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 df=new Pl,uf=new Dl;var Xu={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"}]}},pf={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"]}}}]}}},mf={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 gf(e){return Xu[e]}function ff(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 hf(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 a=e.accounts.map((d)=>d.email),s=a.filter((d,m)=>a.indexOf(d)!==m);if(s.length>0)n.push(`Duplicate email addresses: ${s.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 yf(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
|
+
`)}class El{deployments=new Map;async deploy(e,n){let r=this.generateDeploymentId(),i={id:r,regions:n.regions.map((a)=>({region:a.code,stackName:this.getStackName(e,a.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(r,i);try{let a=n.regions.find((c)=>c.isPrimary)||n.regions[0];await this.deployToRegion(e,a,i);let s=n.regions.filter((c)=>c.code!==a.code);if(await Promise.all(s.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(a){throw i.status="failed",i.endTime=new Date,a}}async deployToRegion(e,n,r){let i=r.regions.find((a)=>a.region===n.code);if(!i)throw Error(`Region deployment not found: ${n.code}`);i.status="deploying",i.startTime=new Date;try{let a=this.createRegionConfig(e,n);await this.deployStack(i.stackName,a,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(a){throw i.status="failed",i.endTime=new Date,i.error=a instanceof Error?a.message:String(a),a}}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 a of e.regions){if(a.status!=="deployed")continue;let s={id:`health-${a.region}`,endpoint:a.outputs?.endpoint,path:n.failover?.healthCheckPath||"/health",region:a.region};r.push(s);let c={name:"example.com",type:"A",region:a.region,setIdentifier:a.region,healthCheckId:s.id,resourceRecords:[a.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,a)=>{let s=n.regions[a];return{id:`origin-${i.region}`,domainName:i.outputs?.endpoint,weight:s?.weight||100}}),status:"Deployed"}}async deployWAF(e){return{webAclId:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6",webAclArn:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6"}}async setupReplication(e,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],a=n[r+1];console.log(`Setting up S3 replication: ${i.region} -> ${a.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((a,s)=>n.regions[s]?.isPrimary)||e.regions[0],i=e.regions.filter((a)=>a.region!==r.region);console.log(`Setting up failover: primary=${r.region}, secondary=${i.map((a)=>a.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 Kg=new El;class wl{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((a)=>a.exportName===n)?.value}createReference(e,n,r,i){let a=`/cross-region/${e}/${r}/${i}`;return this.references.push({sourceRegion:e,targetRegion:n,resourceType:r,resourceId:i,value:a}),a}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 Al{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 Rl{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 Il{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=(a)=>{let s=`${a.name}:${a.region}`;if(n.has(s))return;n.add(s);let c=this.getDependencies(a.name,a.region);for(let u of c)i({name:u.dependsOnStack,region:u.dependsOnRegion});r.push(a)};for(let a of e)i(a);return r}detectCircularDependencies(){let e=new Set,n=new Set,r=(i,a)=>{let s=`${i}:${a}`;if(n.has(s))return!0;if(e.has(s))return!1;e.add(s),n.add(s);let c=this.getDependencies(i,a);for(let u of c)if(r(u.dependsOnStack,u.dependsOnRegion))return!0;return n.delete(s),!1};for(let i of this.dependencies)if(r(i.dependentStack,i.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var Jg=new wl,Xg=new Al,Qg=new Rl,Yg=new Il;var st=[{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 zi(e){return st.find((n)=>n.code===e)}function Zg(){return st}function ef(e){let n=e.toLowerCase();return st.filter((r)=>r.location.toLowerCase().includes(n))}function tf(e){return st.filter((n)=>n.compliance.includes(e))}function rf(e){return st.filter((n)=>n.pricing.tier===e)}function nf(e){return st.some((n)=>n.code===e)}function of(e){if(e.continent==="North America")return zi("us-east-1");if(e.continent==="Europe")return zi("eu-west-1");if(e.continent==="Asia")return zi("ap-southeast-1");return zi("us-east-1")}function sf(e){let n=[...st];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 af(e){let n=zi(e);if(!n)throw Error(`Invalid region: ${e}`);let r=[];for(let i of st){if(i.code===e)continue;let a=ea(n,i),s=ta(n,i);r.push({primary:n,secondary:i,distance:a,sameContinent:s})}return r.sort((i,a)=>{if(i.sameContinent!==a.sameContinent)return i.sameContinent?1:-1;return i.distance-a.distance}),r.slice(0,3)}function ea(e,n){let r={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},i=Qe(e.location),a=Qe(n.location);return Math.abs((r[i]||0)-(r[a]||0))}function ta(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 Ju(e){return`${e.name} (${e.code})`}function cf(e){return e.map((n)=>Ju(n)).join(`
|
|
2740
|
+
`)}function lf(){let e={total:st.length,byContinent:{},byPricingTier:{}};for(let n of st){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 Pl{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,a){let s={roleArn:`arn:aws:iam::${n}:role/${r}`,roleName:r,sourceAccountId:e,targetAccountId:n,permissions:i,externalId:a?.externalId,sessionDuration:a?.sessionDuration||3600};return this.crossAccountRoles.push(s),s}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 Dl{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 df=new Pl,uf=new Dl;var Xu={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"}]}},pf={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"]}}}]}}},mf={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 gf(e){return Xu[e]}function ff(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 hf(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 a=e.accounts.map((d)=>d.email),s=a.filter((d,m)=>a.indexOf(d)!==m);if(s.length>0)n.push(`Duplicate email addresses: ${s.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 yf(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
2741
|
`)}function bf(e={}){let{workflowName:n="Deploy",trigger:r="push",branches:i=["main"],environments:a=["production"],awsRegion:s="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
2742
|
|
|
2743
2743
|
on:
|
|
@@ -3572,7 +3572,7 @@ workflows:
|
|
|
3572
3572
|
requires:
|
|
3573
3573
|
- test
|
|
3574
3574
|
${a}
|
|
3575
|
-
`}class xa{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:a="default-vault"}=e;return this.createBackupPlan({name:"RDS Daily Backup",schedule:r,retentionDays:i,vaultName:a,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:a}=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:a?{CrossRegionCopy:a.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,a={id:`restore-${Date.now()}-${this.restoreCounter++}`,backupId:n,resourceType:r,status:"pending",startTime:new Date,targetRegion:i};return this.restoreJobs.set(a.id,a),setTimeout(()=>{a.status="running"},100),setTimeout(()=>{a.status="completed",a.endTime=new Date},1000),a}async restoreToPointInTime(e){let{sourceResourceArn:n,targetResourceName:r,restoreTime:i,resourceType:a}=e,s={id:`pitr-${Date.now()}-${this.restoreCounter++}`,backupId:`pitr-${i.getTime()}`,resourceType:a,status:"pending",startTime:new Date};return this.restoreJobs.set(s.id,s),console.log(`Restoring ${a} from ${n} to ${r} at ${i.toISOString()}`),setTimeout(()=>{s.status="completed",s.endTime=new Date},2000),s}getRestoreJob(e){return this.restoreJobs.get(e)}listRestoreJobs(){return Array.from(this.restoreJobs.values())}setupCrossRegionReplication(e){let{sourceVault: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 Qu=new xa;class _a{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:a,rto:s=60,rpo:c=5}=e;return this.createDRPlan({name:"RDS Multi-Region DR",primaryRegion:i,secondaryRegion:a,rto:s,rpo:c,resources:[{resourceId:"primary-db",resourceType:"rds",primaryArn:n,secondaryArn:r,replicationEnabled:!0}],runbook:this.generateRDSRunbook(i,a),testSchedule:"0 0 1 * *"})}createDynamoDBDRPlan(e){let{tableArn:n,regions:r,rto:i=15,rpo:a=1}=e;return this.createDRPlan({name:"DynamoDB Global Tables DR",primaryRegion:r[0],secondaryRegion:r[1],rto:i,rpo:a,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(),a=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]");a++,console.log("")}return{success:!0,duration:(Date.now()-i)/1000/60,completedSteps:a}}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 a=Date.now();console.log(`Testing step ${i.order}: ${i.name}`);let s={step:i.name,status:"success",duration:(Date.now()-a)/1000,message:`Successfully validated step ${i.order}`};r.results.push(s)}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 s of e.resources){if(!s.replicationEnabled)n.push(`Resource ${s.resourceId} does not have replication enabled`);if(!s.secondaryArn&&s.resourceType!=="dynamodb")n.push(`Resource ${s.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((s,c)=>s+c.estimatedDuration,0);if(i>e.rto)n.push(`Estimated recovery duration (${i}m) exceeds RTO (${e.rto}m)`);let a=e.runbook.steps.filter((s)=>!s.automatable);if(a.length>0)n.push(`${a.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 Yu=new _a;class Oa{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 Zu=new Oa;class $a{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 ep=new $a;class La{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 tp=new La;class Br{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",...Br.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...Br.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...Br.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...Br.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 rp=new Br;class Ma{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 a=r.activeEnvironment==="blue"?"green":"blue";if(console.log(` Switching to: ${a}`),console.log(`\\n1. Deploying to ${a} environment`),!n)await new Promise((s)=>setTimeout(s,100));if(console.log(`\\n2. Running health checks on ${a} environment`),r.healthCheckConfig){let s=await this.runHealthChecks(r,a,n);if(i.healthChecksPassed=s,!s){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 ${a} environment`),!n)r.activeEnvironment=a,i.switchedAt=new Date;if(console.log(`\\n4. Monitoring ${a} environment`),!n)await new Promise((s)=>setTimeout(s,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 a=0,s=i.healthyThreshold+2;for(let c=0;c<s;c++)if(await new Promise((d)=>setTimeout(d,50)),Math.random()>0.1){if(a++,console.log(` Check ${c+1}: ✓ Healthy (${a}/${i.healthyThreshold})`),a>=i.healthyThreshold)return!0}else a=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 np=new Ma;class ji{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=ji.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=ji.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 a=0;a<r.stages.length;a++){let s=r.stages[a];if(r.currentStage=a,console.log(`Stage ${a+1}/${r.stages.length}: ${s.name}`),console.log(` Traffic: ${s.trafficPercentage}% canary, ${100-s.trafficPercentage}% baseline`),console.log(` Duration: ${s.durationMinutes} minutes`),!n)r.baselineVersion.weight=100-s.trafficPercentage,r.canaryVersion.weight=s.trafficPercentage;if(!await this.monitorStage(r,s,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((a)=>setTimeout(a,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:a,latencyP99:s}=n.alarmThresholds;if(a&&i.canaryErrorRate>a)return console.log(` ⚠ Error rate exceeded threshold: ${i.canaryErrorRate.toFixed(2)}% > ${a}%`),!1;if(s&&i.canaryLatencyP99>s)return console.log(` ⚠ Latency P99 exceeded threshold: ${i.canaryLatencyP99.toFixed(0)}ms > ${s}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 ip=new ji;class Ua{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 a=i.variants.find((c)=>c.id===n);if(!a)throw Error(`Variant not found: ${n}`);let s=a.trafficPercentage;a.trafficPercentage=r,a.weight=r,console.log(`Updated ${a.name} traffic: ${s}% → ${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 a=n.metrics.variants.control||n.metrics.variants[n.variants[0].id],s=n.metrics.variants[r.id],c=(s.conversionRate-a.conversionRate)/a.conversionRate*100,u=100,d=s.requests>u&&a.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((a)=>a.id===n);if(!i)throw Error(`Variant not found: ${n}`);r.variants.forEach((a)=>{if(a.id===n)a.trafficPercentage=100,a.weight=100;else a.trafficPercentage=0,a.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 a=Math.floor(Math.random()*1000)+500,s=Math.floor(a*(Math.random()*0.1+0.05)),c=s/a*100;n[i.id]={requests:a,conversions:s,conversionRate:c,averageLatency:150+Math.random()*100,errorRate:Math.random()*0.5,revenue:s*(Math.random()*50+100)},r+=a}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';
|
|
3575
|
+
`}class xa{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:a="default-vault"}=e;return this.createBackupPlan({name:"RDS Daily Backup",schedule:r,retentionDays:i,vaultName:a,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:a}=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:a?{CrossRegionCopy:a.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,a={id:`restore-${Date.now()}-${this.restoreCounter++}`,backupId:n,resourceType:r,status:"pending",startTime:new Date,targetRegion:i};return this.restoreJobs.set(a.id,a),setTimeout(()=>{a.status="running"},100),setTimeout(()=>{a.status="completed",a.endTime=new Date},1000),a}async restoreToPointInTime(e){let{sourceResourceArn:n,targetResourceName:r,restoreTime:i,resourceType:a}=e,s={id:`pitr-${Date.now()}-${this.restoreCounter++}`,backupId:`pitr-${i.getTime()}`,resourceType:a,status:"pending",startTime:new Date};return this.restoreJobs.set(s.id,s),console.log(`Restoring ${a} from ${n} to ${r} at ${i.toISOString()}`),setTimeout(()=>{s.status="completed",s.endTime=new Date},2000),s}getRestoreJob(e){return this.restoreJobs.get(e)}listRestoreJobs(){return Array.from(this.restoreJobs.values())}setupCrossRegionReplication(e){let{sourceVault: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 Qu=new xa;class _a{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:a,rto:s=60,rpo:c=5}=e;return this.createDRPlan({name:"RDS Multi-Region DR",primaryRegion:i,secondaryRegion:a,rto:s,rpo:c,resources:[{resourceId:"primary-db",resourceType:"rds",primaryArn:n,secondaryArn:r,replicationEnabled:!0}],runbook:this.generateRDSRunbook(i,a),testSchedule:"0 0 1 * *"})}createDynamoDBDRPlan(e){let{tableArn:n,regions:r,rto:i=15,rpo:a=1}=e;return this.createDRPlan({name:"DynamoDB Global Tables DR",primaryRegion:r[0],secondaryRegion:r[1],rto:i,rpo:a,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(),a=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]");a++,console.log("")}return{success:!0,duration:(Date.now()-i)/1000/60,completedSteps:a}}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 a=Date.now();console.log(`Testing step ${i.order}: ${i.name}`);let s={step:i.name,status:"success",duration:(Date.now()-a)/1000,message:`Successfully validated step ${i.order}`};r.results.push(s)}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 s of e.resources){if(!s.replicationEnabled)n.push(`Resource ${s.resourceId} does not have replication enabled`);if(!s.secondaryArn&&s.resourceType!=="dynamodb")n.push(`Resource ${s.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((s,c)=>s+c.estimatedDuration,0);if(i>e.rto)n.push(`Estimated recovery duration (${i}m) exceeds RTO (${e.rto}m)`);let a=e.runbook.steps.filter((s)=>!s.automatable);if(a.length>0)n.push(`${a.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 Yu=new _a;class Oa{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 Zu=new Oa;class $a{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 ep=new $a;class La{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 tp=new La;class jr{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",...jr.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...jr.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...jr.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...jr.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 rp=new jr;class Ma{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 a=r.activeEnvironment==="blue"?"green":"blue";if(console.log(` Switching to: ${a}`),console.log(`\\n1. Deploying to ${a} environment`),!n)await new Promise((s)=>setTimeout(s,100));if(console.log(`\\n2. Running health checks on ${a} environment`),r.healthCheckConfig){let s=await this.runHealthChecks(r,a,n);if(i.healthChecksPassed=s,!s){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 ${a} environment`),!n)r.activeEnvironment=a,i.switchedAt=new Date;if(console.log(`\\n4. Monitoring ${a} environment`),!n)await new Promise((s)=>setTimeout(s,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 a=0,s=i.healthyThreshold+2;for(let c=0;c<s;c++)if(await new Promise((d)=>setTimeout(d,50)),Math.random()>0.1){if(a++,console.log(` Check ${c+1}: ✓ Healthy (${a}/${i.healthyThreshold})`),a>=i.healthyThreshold)return!0}else a=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 np=new Ma;class Hi{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=Hi.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=Hi.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 a=0;a<r.stages.length;a++){let s=r.stages[a];if(r.currentStage=a,console.log(`Stage ${a+1}/${r.stages.length}: ${s.name}`),console.log(` Traffic: ${s.trafficPercentage}% canary, ${100-s.trafficPercentage}% baseline`),console.log(` Duration: ${s.durationMinutes} minutes`),!n)r.baselineVersion.weight=100-s.trafficPercentage,r.canaryVersion.weight=s.trafficPercentage;if(!await this.monitorStage(r,s,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((a)=>setTimeout(a,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:a,latencyP99:s}=n.alarmThresholds;if(a&&i.canaryErrorRate>a)return console.log(` ⚠ Error rate exceeded threshold: ${i.canaryErrorRate.toFixed(2)}% > ${a}%`),!1;if(s&&i.canaryLatencyP99>s)return console.log(` ⚠ Latency P99 exceeded threshold: ${i.canaryLatencyP99.toFixed(0)}ms > ${s}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 ip=new Hi;class Ua{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 a=i.variants.find((c)=>c.id===n);if(!a)throw Error(`Variant not found: ${n}`);let s=a.trafficPercentage;a.trafficPercentage=r,a.weight=r,console.log(`Updated ${a.name} traffic: ${s}% → ${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 a=n.metrics.variants.control||n.metrics.variants[n.variants[0].id],s=n.metrics.variants[r.id],c=(s.conversionRate-a.conversionRate)/a.conversionRate*100,u=100,d=s.requests>u&&a.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((a)=>a.id===n);if(!i)throw Error(`Variant not found: ${n}`);r.variants.forEach((a)=>{if(a.id===n)a.trafficPercentage=100,a.weight=100;else a.trafficPercentage=0,a.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 a=Math.floor(Math.random()*1000)+500,s=Math.floor(a*(Math.random()*0.1+0.05)),c=s/a*100;n[i.id]={requests:a,conversions:s,conversionRate:c,averageLatency:150+Math.random()*100,errorRate:Math.random()*0.5,revenue:s*(Math.random()*50+100)},r+=a}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
3576
|
|
|
3577
3577
|
exports.handler = (event, _context, _callback) => {
|
|
3578
3578
|
const request = event.Records[0].cf.request;
|
|
@@ -3629,7 +3629,7 @@ exports.handler = (event, _context, _callback) => {
|
|
|
3629
3629
|
| filter @message like /ERROR/
|
|
3630
3630
|
| stats count() as error_count by @message
|
|
3631
3631
|
| 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++}`,a=this.createLogGroup({name:e,retentionDays:r});return n.forEach((s)=>{this.createMetricFilter(a.id,{name:s.metric,filterPattern:s.pattern,metricTransformations:[{metricName:s.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 Ba;class
|
|
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++}`,a=this.createLogGroup({name:e,retentionDays:r});return n.forEach((s)=>{this.createMetricFilter(a.id,{name:s.metric,filterPattern:s.pattern,metricTransformations:[{metricName:s.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 Ba;class Vr{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
3633
|
const synthetics = require('Synthetics');
|
|
3634
3634
|
const log = require('SyntheticsLogger');
|
|
3635
3635
|
|
|
@@ -3649,7 +3649,7 @@ const heartbeat = async function () {
|
|
|
3649
3649
|
exports.handler = async () => {
|
|
3650
3650
|
return await heartbeat();
|
|
3651
3651
|
};
|
|
3652
|
-
`;return this.createCanary({name:e.name,description:`Heartbeat monitor for ${e.url}`,runtimeVersion:
|
|
3652
|
+
`;return this.createCanary({name:e.name,description:`Heartbeat monitor for ${e.url}`,runtimeVersion:Vr.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
3653
|
const synthetics = require('Synthetics');
|
|
3654
3654
|
const log = require('SyntheticsLogger');
|
|
3655
3655
|
|
|
@@ -3678,7 +3678,7 @@ const apiCheck = async function () {
|
|
|
3678
3678
|
exports.handler = async () => {
|
|
3679
3679
|
return await apiCheck();
|
|
3680
3680
|
};
|
|
3681
|
-
`;return this.createCanary({name:e.name,description:`API monitor for ${e.baseUrl}`,runtimeVersion:
|
|
3681
|
+
`;return this.createCanary({name:e.name,description:`API monitor for ${e.baseUrl}`,runtimeVersion:Vr.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
3682
|
const synthetics = require('Synthetics');
|
|
3683
3683
|
const log = require('SyntheticsLogger');
|
|
3684
3684
|
|
|
@@ -3698,7 +3698,7 @@ const visualCheck = async function () {
|
|
|
3698
3698
|
exports.handler = async () => {
|
|
3699
3699
|
return await visualCheck();
|
|
3700
3700
|
};
|
|
3701
|
-
`;return this.createCanary({name:e.name,description:`Visual regression monitor for ${e.url}`,runtimeVersion:
|
|
3701
|
+
`;return this.createCanary({name:e.name,description:`Visual regression monitor for ${e.url}`,runtimeVersion:Vr.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
3702
|
const synthetics = require('Synthetics');
|
|
3703
3703
|
const log = require('SyntheticsLogger');
|
|
3704
3704
|
|
|
@@ -3720,7 +3720,7 @@ const workflowCheck = async function () {
|
|
|
3720
3720
|
exports.handler = async () => {
|
|
3721
3721
|
return await workflowCheck();
|
|
3722
3722
|
};
|
|
3723
|
-
`;return this.createCanary({name:e.name,description:e.description,runtimeVersion:
|
|
3723
|
+
`;return this.createCanary({name:e.name,description:e.description,runtimeVersion:Vr.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 a={id:`alarm-${Date.now()}-${this.alarmCounter++}`,...n};if(!r.alarms)r.alarms=[];return r.alarms.push(a),a}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 cp=new Vr;class xl{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(),a=[],s=[];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
3724
|
`),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
3725
|
`)}else console.log(`[SKIPPED - DRY RUN]
|
|
3726
3726
|
`);a.push(u.version)}catch(d){if(console.error(`✗ Failed: ${d instanceof Error?d.message:String(d)}
|
|
@@ -5846,7 +5846,7 @@ catch (error) {
|
|
|
5846
5846
|
};
|
|
5847
5847
|
}
|
|
5848
5848
|
};
|
|
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:Ut.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
|
|
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:Ut.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 at{static CallbackRequestCode=`
|
|
5850
5850
|
const { DynamoDBClient, PutItemCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
|
|
5851
5851
|
const { ConnectClient, StartOutboundVoiceContactCommand } = require('@aws-sdk/client-connect');
|
|
5852
5852
|
const { SNSClient, PublishCommand } = require('@aws-sdk/client-sns');
|
|
@@ -6136,7 +6136,7 @@ catch (error) {
|
|
|
6136
6136
|
return { statusCode: 500, error: error.message };
|
|
6137
6137
|
}
|
|
6138
6138
|
};
|
|
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:
|
|
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:at.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:at.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 Ht{static CampaignManagerCode=`
|
|
6140
6140
|
const { DynamoDBClient, PutItemCommand, GetItemCommand, UpdateItemCommand, ScanCommand } = require('@aws-sdk/client-dynamodb');
|
|
6141
6141
|
|
|
6142
6142
|
const dynamodb = new DynamoDBClient({});
|
|
@@ -7236,7 +7236,7 @@ function unmarshallTest(item) {
|
|
|
7236
7236
|
|
|
7237
7237
|
return test;
|
|
7238
7238
|
}
|
|
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,a=0;for(let s=0;s<e.variants.length;s++)if(a+=e.trafficSplit[s],i<a)return e.variants[s];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 a of e.variants.slice(1)){let s=me.getMetricValue(a,n);if(s>i)i=s,r=a}return r}static calculateSignificance(e,n,r){let i=e.stats.sent,a=n.stats.sent;if(i<30||a<30)return 0;let s=me.getMetricValue(e,r)/100,c=me.getMetricValue(n,r)/100,u=(s*i+c*a)/(i+a),d=Math.sqrt(u*(1-u)*(1/i+1/a));if(d===0)return 0;let m=Math.abs(s-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 rd{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,...a}=e,s={id:n,name:r,queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${r}`,...a};return this.queues.set(n,s),this.createDeduplicationConfig({queueId:n,contentBasedDeduplication:e.contentBasedDeduplication,deduplicationInterval:300}),s}createHighThroughputFIFO(e){return this.createFIFOQueue({name:e.name,contentBasedDeduplication:e.contentBasedDeduplication??!0,deduplicationScope:"messageGroup",fifoThroughputLimit:"perMessageGroupId",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createStandardFIFO(e){return this.createFIFOQueue({name:e.name,contentBasedDeduplication:e.contentBasedDeduplication??!1,deduplicationScope:"queue",fifoThroughputLimit:"perQueue",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createDeduplicationConfig(e){let 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++}`,a=this.generateSequenceNumber(),s={id:i,messageId:i,messageGroupId:e.messageGroupId,messageDeduplicationId:e.messageDeduplicationId,body:e.messageBody,attributes:e.messageAttributes||{},sentTimestamp:new Date,sequenceNumber:a};return this.messages.set(i,s),this.updateMessageGroup(e.queueId,e.messageGroupId),s}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,a)=>i.sequenceNumber.localeCompare(a.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 th=new rd;class nd{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((a)=>a.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 a=i[i.length-1],s=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:a.approximateNumberOfMessages,avgAge:d,messagesReceived:s,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,a)=>a.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 rh=new nd;class id{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 s=0;s<e.messageCount;s++)i.push({id:`msg-${n}-${s}`,messageId:`${n}-${s}`,body:`Message ${s}`,receiptHandle:`receipt-${n}-${s}`,attributes:{},status:"pending"});let a={id:n,configId:e.configId,messages:i,status:"pending",processedCount:0,failedCount:0};return this.jobs.set(n,a),a}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 a of i)await this.processBatch(a,r);return n.processedCount=n.messages.filter((a)=>a.status==="success").length,n.failedCount=n.messages.filter((a)=>a.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((s)=>setTimeout(s,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++}`,a=n.messages.filter((g)=>g.status==="success").map((g)=>g.processingTime||0).filter((g)=>g>0),s=a.length>0?a.reduce((g,y)=>g+y,0)/a.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:s,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,a=n.reduce((c,u)=>c+u.errorRate,0)/n.length,s=n.reduce((c,u)=>c+u.averageProcessingTime,0)/n.length;return{totalJobsProcessed:n.length,totalMessagesProcessed:r,averageThroughput:i,averageErrorRate:a,averageProcessingTime:s}}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 nh=new id;class od{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((a)=>a.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=[],a=[],s="healthy";if(r.approximateNumberOfMessages>1e4)s="critical",i.push("Large message backlog detected"),a.push("Increase consumer capacity");else if(r.approximateNumberOfMessages>1000)s="warning",i.push("Growing message backlog"),a.push("Monitor consumer performance");if(r.oldestMessageAge&&r.oldestMessageAge>3600){if(s!=="critical")s="warning";i.push("Old messages in queue"),a.push("Review message processing")}if(r.approximateNumberOfMessagesDelayed>100){if(s!=="critical")s="warning";i.push("High number of delayed messages")}return{status:s,issues:i,recommendations:a}}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 ih=new od;import{deflateRawSync as ia}from"node:zlib";var oa=(()=>{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 ns(e){let n=4294967295;for(let r=0;r<e.length;r++)n=oa[(n^e[r])&255]^n>>>8;return(n^4294967295)>>>0}function rs(e){if(typeof e==="string")return Buffer.from(e,"utf-8");if(Buffer.isBuffer(e))return e;return Buffer.from(e)}function is(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 Dt(e){let n=[],r=[],i=0;for(let c of e){let u=rs(c.data),d=ia(u),m=ns(u),p=Buffer.from(c.name.replace(/\\/g,"/"),"utf-8"),{time:g,date:y}=is(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 a=Buffer.concat(r),s=Buffer.alloc(22);return s.writeUInt32LE(101010256,0),s.writeUInt16LE(0,4),s.writeUInt16LE(0,6),s.writeUInt16LE(e.length,8),s.writeUInt16LE(e.length,10),s.writeUInt32LE(a.length,12),s.writeUInt32LE(i,16),s.writeUInt16LE(0,20),Buffer.concat([...n,a,s])}function sd(e){let n=e.adapterImport??"./adapter",r=e.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
|
|
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,a=0;for(let s=0;s<e.variants.length;s++)if(a+=e.trafficSplit[s],i<a)return e.variants[s];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 a of e.variants.slice(1)){let s=me.getMetricValue(a,n);if(s>i)i=s,r=a}return r}static calculateSignificance(e,n,r){let i=e.stats.sent,a=n.stats.sent;if(i<30||a<30)return 0;let s=me.getMetricValue(e,r)/100,c=me.getMetricValue(n,r)/100,u=(s*i+c*a)/(i+a),d=Math.sqrt(u*(1-u)*(1/i+1/a));if(d===0)return 0;let m=Math.abs(s-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 rd{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,...a}=e,s={id:n,name:r,queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${r}`,...a};return this.queues.set(n,s),this.createDeduplicationConfig({queueId:n,contentBasedDeduplication:e.contentBasedDeduplication,deduplicationInterval:300}),s}createHighThroughputFIFO(e){return this.createFIFOQueue({name:e.name,contentBasedDeduplication:e.contentBasedDeduplication??!0,deduplicationScope:"messageGroup",fifoThroughputLimit:"perMessageGroupId",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createStandardFIFO(e){return this.createFIFOQueue({name:e.name,contentBasedDeduplication:e.contentBasedDeduplication??!1,deduplicationScope:"queue",fifoThroughputLimit:"perQueue",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createDeduplicationConfig(e){let 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++}`,a=this.generateSequenceNumber(),s={id:i,messageId:i,messageGroupId:e.messageGroupId,messageDeduplicationId:e.messageDeduplicationId,body:e.messageBody,attributes:e.messageAttributes||{},sentTimestamp:new Date,sequenceNumber:a};return this.messages.set(i,s),this.updateMessageGroup(e.queueId,e.messageGroupId),s}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,a)=>i.sequenceNumber.localeCompare(a.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 th=new rd;class nd{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((a)=>a.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 a=i[i.length-1],s=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:a.approximateNumberOfMessages,avgAge:d,messagesReceived:s,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,a)=>a.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 rh=new nd;class id{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 s=0;s<e.messageCount;s++)i.push({id:`msg-${n}-${s}`,messageId:`${n}-${s}`,body:`Message ${s}`,receiptHandle:`receipt-${n}-${s}`,attributes:{},status:"pending"});let a={id:n,configId:e.configId,messages:i,status:"pending",processedCount:0,failedCount:0};return this.jobs.set(n,a),a}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 a of i)await this.processBatch(a,r);return n.processedCount=n.messages.filter((a)=>a.status==="success").length,n.failedCount=n.messages.filter((a)=>a.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((s)=>setTimeout(s,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++}`,a=n.messages.filter((g)=>g.status==="success").map((g)=>g.processingTime||0).filter((g)=>g>0),s=a.length>0?a.reduce((g,y)=>g+y,0)/a.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:s,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,a=n.reduce((c,u)=>c+u.errorRate,0)/n.length,s=n.reduce((c,u)=>c+u.averageProcessingTime,0)/n.length;return{totalJobsProcessed:n.length,totalMessagesProcessed:r,averageThroughput:i,averageErrorRate:a,averageProcessingTime:s}}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 nh=new id;class od{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((a)=>a.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=[],a=[],s="healthy";if(r.approximateNumberOfMessages>1e4)s="critical",i.push("Large message backlog detected"),a.push("Increase consumer capacity");else if(r.approximateNumberOfMessages>1000)s="warning",i.push("Growing message backlog"),a.push("Monitor consumer performance");if(r.oldestMessageAge&&r.oldestMessageAge>3600){if(s!=="critical")s="warning";i.push("Old messages in queue"),a.push("Review message processing")}if(r.approximateNumberOfMessagesDelayed>100){if(s!=="critical")s="warning";i.push("High number of delayed messages")}return{status:s,issues:i,recommendations:a}}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 ih=new od;import{deflateRawSync as ia}from"node:zlib";var oa=(()=>{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 as(e){let n=4294967295;for(let r=0;r<e.length;r++)n=oa[(n^e[r])&255]^n>>>8;return(n^4294967295)>>>0}function ss(e){if(typeof e==="string")return Buffer.from(e,"utf-8");if(Buffer.isBuffer(e))return e;return Buffer.from(e)}function os(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 Dt(e){let n=[],r=[],i=0;for(let c of e){let u=ss(c.data),d=ia(u),m=as(u),p=Buffer.from(c.name.replace(/\\/g,"/"),"utf-8"),{time:g,date:y}=os(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 a=Buffer.concat(r),s=Buffer.alloc(22);return s.writeUInt32LE(101010256,0),s.writeUInt16LE(0,4),s.writeUInt16LE(0,6),s.writeUInt16LE(e.length,8),s.writeUInt16LE(e.length,10),s.writeUInt32LE(a.length,12),s.writeUInt32LE(i,16),s.writeUInt16LE(0,20),Buffer.concat([...n,a,s])}function sd(e){let n=e.adapterImport??"./adapter",r=e.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
|
|
7240
7240
|
import * as __userModule from ${JSON.stringify(r)}
|
|
7241
7241
|
import { resolveApp, createHandlers } from ${JSON.stringify(n)}
|
|
7242
7242
|
|
|
@@ -7246,9 +7246,9 @@ const __handlers = createHandlers(__app)
|
|
|
7246
7246
|
export const http = __handlers.http
|
|
7247
7247
|
export const queue = __handlers.queue
|
|
7248
7248
|
export const cli = __handlers.cli
|
|
7249
|
-
`}import{execSync as
|
|
7249
|
+
`}import{execSync as cs}from"node:child_process";import{createHash as ls}from"node:crypto";import{cpSync as us,mkdtempSync as ds,rmSync as ms,writeFileSync as ps}from"node:fs";import{tmpdir as gs}from"node:os";import{dirname as ys,isAbsolute as fs,join as xe,resolve as hs}from"node:path";import{fileURLToPath as bs}from"node:url";var Ss=["adapter.ts","recursion.ts","auto-recursion.ts"];function As(){return xe(ys(bs(import.meta.url)),"runtime")}function gp(e,n,r){for(let i of e??[])r?.(`build: ${i}`),cs(i,{stdio:"inherit",cwd:n})}function es(e){return ls("sha256").update(e).digest("hex")}function Ga(e,n,r){return`deployments/${e}/${n}/${r}.zip`}async function In(e){let n=hs(e.projectRoot??process.cwd()),{app:r}=e;if(!e.skipBuild)gp(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 a=fs(i)?i:xe(n,i),s=ds(xe(gs(),"tscloud-pkg-"));try{for(let y of Ss)us(xe(As(),y),xe(s,y));let c=xe(s,"bootstrap.ts");ps(c,sd({entryImport:a,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
7250
|
`);throw Error(`serverless app bundle failed:
|
|
7251
|
-
${y}`)}let d=u.outputs[0],m=Buffer.from(await d.arrayBuffer()),p="index",g=Dt([{name:`${p}.mjs`,data:m}]);return{zip:g,bundle:m,sha256:Qo(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{ls(s,{recursive:!0,force:!0})}}var fp=["18","20","22"];function bs(e){if(!e)return"22";let n=String(e).match(/(\d+)/);return n?n[1]:"22"}function Vi(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=bs(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&fp.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 Qt(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[a,s]=Object.entries(i)[0];return{name:`${n}-${r}-${a}`,concurrency:s}})}function Wa(e,n,r){return Qt(e,n,r).map((i)=>i.name)}function Ka(e){let{app:n,environment:r,handlers:i}=e,a=e.config.project.slug,s=Vi(n).lambdaRuntime,c=n.architecture??"x86_64",u=e.config.project.region,d={http:`${a}-${r}-http`,queue:`${a}-${r}-queue`,cli:`${a}-${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=Qt(n,a,r),p=m.map((x)=>x.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",C=Boolean(n.assets),P=_i(a,r),E=n.tmpStorage??512,v={},I={},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:${a}-${r}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${a}/${r}/*`),t.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${a}/${r}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[t.sub(`arn:aws:s3:::${P}`),t.sub(`arn:aws:s3:::${P}/*`),...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}:${a}-${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/${a}-${r}-cache*`)});let N=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(n.vpc?.subnets?.length)N.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(n.lambdaInsights)N.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");v.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${a}-${r}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:N,Policies:D}};let M=(x)=>({TSCLOUD_LAMBDA_MODE:x,TSCLOUD_ENV:r,...n.octane?{TSCLOUD_OCTANE:"1"}:{},...n.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...S?{TSCLOUD_CACHE_TABLE:`${a}-${r}-cache`}:{},...g?{TSCLOUD_QUEUE:p[0]}:{},...n.env??{}}),F=Boolean(n.efs),O=typeof n.efs==="object"?n.efs:{},G=O.mountPath??"/mnt/local",U=F&&!O.accessPointArn,ce=O.accessPointArn??(U?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)||F;if(K&&!J)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let Q=J?{VpcConfig:{SubnetIds:q,SecurityGroupIds:[...n.vpc?.securityGroups??[],...K?[t.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},ge=U?q.map((x,_)=>`EfsMountTarget${_}`):[],Te=F?{FileSystemConfigs:[{Arn:ce,LocalMountPath:G}]}:{};if(F)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function te(x,_,V,W,ee,mt,Be,he=E){v[`${x}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${_}`,RetentionInDays:y}};let Fe=[...e.runtimeLayers??[],...n.lambdaInsights?[n.lambdaInsights.layerArn]:[]],rn=f?{PackageType:"Image",Code:{ImageUri:t.ref("ImageUri")},...n.kind==="php"?{}:{ImageConfig:{Command:[V]}}}:{Runtime:s,Handler:V,Code:{S3Bucket:t.ref("ArtifactBucket"),S3Key:t.ref("ArtifactKey")},...Fe.length?{Layers:[...new Set(Fe)]}:{}};v[x]={Type:"AWS::Lambda::Function",DependsOn:[`${x}LogGroup`,...ge],Properties:{FunctionName:_,Architectures:[c],MemorySize:ee,Timeout:mt,Role:t.getAtt("AppRole","Arn"),Environment:{Variables:M(W)},EphemeralStorage:{Size:he},...rn,...Be!==void 0?{ReservedConcurrentExecutions:Be}:{},...Q,...Te}}}if(te("HttpFunction",d.http,i.http,"http",n.memory??1024,n.timeout??28,n.concurrency,E),te("CliFunction",d.cli,i.cli,"cli",n.cliMemory??1024,n.cliTimeout??900,void 0,n.cliTmpStorage??E),g)te("QueueFunction",d.queue,i.queue,"queue",n.queueMemory??1024,n.queueTimeout??120,void 0,n.queueTmpStorage??E);let Z=(n.provisionedConcurrency??0)>0?n.provisionedConcurrency:0,re=["HttpFunction","CliFunction",...g?["QueueFunction"]:[]];if(Z)for(let x of re)v[`${x}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:t.ref(x)}},v[`${x}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:t.ref(x),Name:"live",FunctionVersion:t.getAtt(`${x}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:Z}}};let fe=(x)=>Z?t.ref(`${x}Alias`):t.getAtt(x,"Arn"),ae=(x)=>Z?t.ref(`${x}Alias`):t.ref(x);v.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${a}-${r}`,ProtocolType:"HTTP"}},v.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:t.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:fe("HttpFunction"),PayloadFormatVersion:"2.0"}},v.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:t.ref("HttpApi"),RouteKey:"$default",Target:t.join("/",["integrations",t.ref("HttpIntegration")])}},v.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},v.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ae("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},I.HttpApiEndpoint={Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint")},I.HttpApiId={Description:"HTTP API id",Value:t.ref("HttpApi")};let ue=(Array.isArray(n.domain)?n.domain:n.domain?[n.domain]:[]).filter(Boolean);if(ue.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 x=n.certificateArn;if(!x)v.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:ue[0],...ue.length>1?{SubjectAlternativeNames:ue.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:ue.map((_)=>({DomainName:_,HostedZoneId:n.hostedZoneId}))}},x=t.ref("HttpCertificate");ue.forEach((_,V)=>{let W=`HttpDomain${V}`;if(v[W]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:_,DomainNameConfigurations:[{CertificateArn:x,EndpointType:"REGIONAL"}]}},v[`HttpApiMapping${V}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:t.ref("HttpApi"),DomainName:t.ref(W),Stage:"$default"}},n.hostedZoneId)v[`HttpDomainRecord${V}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:_,Type:"A",AliasTarget:{DNSName:t.getAtt(W,"RegionalDomainName"),HostedZoneId:t.getAtt(W,"RegionalHostedZoneId")}}};I[`CustomDomain${V}`]={Description:`Custom domain ${_}`,Value:_},I[`CustomDomainTarget${V}`]={Description:`Point ${_} (CNAME/alias) at this APIGW regional domain`,Value:t.getAtt(W,"RegionalDomainName")}})}if(g)v.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${a}-${r}-dlq`,MessageRetentionPeriod:1209600}},m.forEach((x,_)=>{let V=`AppQueue${_}`,W=n.queueTimeout??120;v[V]={Type:"AWS::SQS::Queue",Properties:{QueueName:x.name,VisibilityTimeout:Math.min(43200,W*6),RedrivePolicy:{deadLetterTargetArn:t.getAtt("AppQueueDlq","Arn"),maxReceiveCount:n.queueTries??3}}};let ee=x.concurrency??n.queueConcurrency;v[`${V}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:t.getAtt(V,"Arn"),FunctionName:ae("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...ee?{ScalingConfig:{MaximumConcurrency:Math.max(2,ee)}}:{}}},I[`QueueUrl${_}`]={Description:`Queue URL: ${x.name}`,Value:t.ref(V)}});if(h)v.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${a}-${r}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:fe("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},v.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 _={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},V=(n.warmFunctions??["http"]).filter((W)=>W!=="queue"||g);for(let W of V){let ee=W.charAt(0).toUpperCase()+W.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);v[`Warmer${ee}Rule${he}`]={Type:"AWS::Events::Rule",Properties:{Name:`${a}-${r}-warmer-${W}-${he}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Fe},(rn,lr)=>({Id:`warm-${W}-${he}-${lr}`,Arn:t.getAtt(_[W],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Be+=Fe}v[`Warmer${ee}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:t.ref(_[W]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${a}-${r}-warmer-${W}-*`)}}}}if(S)v.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-${r}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},I.CacheTableName={Description:"DynamoDB cache table",Value:t.ref("CacheTable")};if(C){if(v.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:P,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},v.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${a}-${r}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},v.AssetsDistribution={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,DefaultCacheBehavior:{TargetOriginId:"assets",ViewerProtocolPolicy:"redirect-to-https",Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},Origins:[{Id:"assets",DomainName:t.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:t.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...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.`);v.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:n.assetDomain,HostedZoneId:n.hostedZoneId}]}}}if(n.hostedZoneId)v.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:n.assetDomain,Type:"A",AliasTarget:{DNSName:t.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};I.AssetDomain={Description:"Custom asset CDN host",Value:n.assetDomain}}v.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:t.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:t.sub(`arn:aws:s3:::${P}/*`),Condition:{StringEquals:{"AWS:SourceArn":t.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},I.AssetsBucketName={Description:"Assets bucket",Value:t.ref("AssetsBucket")},I.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:t.getAtt("AssetsDistribution","DomainName")}}if(n.firewall?.enabled){let x=[],_=0;if(n.firewall.rateLimit)x.push({Name:"rate-limit",Priority:_++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:n.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-${r}-rate`}});let V={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let W of n.firewall.rules??[]){let ee=V[W];if(!ee)continue;x.push({Name:`managed-${W}`,Priority:_++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:ee}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-${r}-${W}`}})}v.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${a}-${r}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:x,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-${r}-waf`}}},I.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.");v.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:n.vpc.id,GroupDescription:`${a}-${r} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(U)v.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${a}-${r}-efs`}]}},q.forEach((x,_)=>{v[`EfsMountTarget${_}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:t.ref("EfsFileSystem"),SubnetId:x,SecurityGroups:[t.getAtt("DataSecurityGroup","GroupId")]}}}),v.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:t.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},I.EfsFileSystemId={Description:"EFS file system id",Value:t.ref("EfsFileSystem")};if(n.cache?.driver==="elasticache")v.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${a}-${r} cache subnets`,SubnetIds:q}},v.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${a}-${r}-cache`,ReplicationGroupDescription:`${a}-${r} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},I.CacheEndpoint={Description:"Redis primary endpoint",Value:t.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(n.database?.connection==="aurora-serverless")v.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${a}-${r} db subnets`,SubnetIds:q}},v.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${a}/${r}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},v.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${a}-${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")]}},v.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:t.ref("DbCluster")}},I.DbEndpoint={Description:"Aurora cluster endpoint",Value:t.getAtt("DbCluster","Endpoint.Address")};if(n.rdsProxy&&n.database?.connection==="aurora-serverless")v.DbProxyRole={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"read-db-secret",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:t.ref("DbSecret")}]}}]}},v.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof n.rdsProxy==="object"&&n.rdsProxy.name?n.rdsProxy.name:`${a}-${r}-proxy`,EngineFamily:"MYSQL",RoleArn:t.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:t.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:q,VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},v.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:t.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[t.ref("DbCluster")]}},I.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:t.getAtt("DbProxy","Endpoint")};if(I.HttpFunctionName={Description:"HTTP function name",Value:t.ref("HttpFunction")},I.CliFunctionName={Description:"CLI function name",Value:t.ref("CliFunction")},g)I.QueueFunctionName={Description:"Queue function name",Value:t.ref("QueueFunction")};let Ee={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${a}-${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:v,Outputs:I},Le={};for(let x of Object.values(v))Le[x.Type]=(Le[x.Type]??0)+1;return{template:Ee,functionNames:d,queueNames:p,resourceSummary:Le}}var hp=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function yp(e){let n=`php${e.replace(".","")}`;return hp.map((r)=>`${n}-php-${r}`)}function Ja(e,n){let r=`php${e.replace(".","")}`,i=yp(e).join(" \\\n "),a=`/opt/remi/${r}/root`,s=`/etc/opt/remi/${r}`;return`${n?`FROM almalinux:9 AS ${n}`:"FROM almalinux:9"}
|
|
7251
|
+
${y}`)}let d=u.outputs[0],m=Buffer.from(await d.arrayBuffer()),p="index",g=Dt([{name:`${p}.mjs`,data:m}]);return{zip:g,bundle:m,sha256:es(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{ms(s,{recursive:!0,force:!0})}}var fp=["18","20","22"];function Cs(e){if(!e)return"22";let n=String(e).match(/(\d+)/);return n?n[1]:"22"}function qi(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=Cs(e.runtimeVersion);if(e.runtime!=="provided.al2023"&&fp.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 Qt(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[a,s]=Object.entries(i)[0];return{name:`${n}-${r}-${a}`,concurrency:s}})}function Wa(e,n,r){return Qt(e,n,r).map((i)=>i.name)}function Ka(e){let{app:n,environment:r,handlers:i}=e,a=e.config.project.slug,s=qi(n).lambdaRuntime,c=n.architecture??"x86_64",u=e.config.project.region,d={http:`${a}-${r}-http`,queue:`${a}-${r}-queue`,cli:`${a}-${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=Qt(n,a,r),p=m.map((x)=>x.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",C=Boolean(n.assets),P=Li(a,r),E=n.tmpStorage??512,v={},I={},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:${a}-${r}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[t.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${a}/${r}/*`),t.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${a}/${r}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[t.sub(`arn:aws:s3:::${P}`),t.sub(`arn:aws:s3:::${P}/*`),...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}:${a}-${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/${a}-${r}-cache*`)});let N=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(n.vpc?.subnets?.length)N.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(n.lambdaInsights)N.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");v.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${a}-${r}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:N,Policies:D}};let M=(x)=>({TSCLOUD_LAMBDA_MODE:x,TSCLOUD_ENV:r,...n.octane?{TSCLOUD_OCTANE:"1"}:{},...n.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...S?{TSCLOUD_CACHE_TABLE:`${a}-${r}-cache`}:{},...g?{TSCLOUD_QUEUE:p[0]}:{},...n.env??{}}),F=Boolean(n.efs),O=typeof n.efs==="object"?n.efs:{},G=O.mountPath??"/mnt/local",U=F&&!O.accessPointArn,ce=O.accessPointArn??(U?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)||F;if(K&&!J)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let Q=J?{VpcConfig:{SubnetIds:q,SecurityGroupIds:[...n.vpc?.securityGroups??[],...K?[t.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},ge=U?q.map((x,_)=>`EfsMountTarget${_}`):[],Te=F?{FileSystemConfigs:[{Arn:ce,LocalMountPath:G}]}:{};if(F)D[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function te(x,_,V,W,ee,mt,Be,he=E){v[`${x}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${_}`,RetentionInDays:y}};let Fe=[...e.runtimeLayers??[],...n.lambdaInsights?[n.lambdaInsights.layerArn]:[]],rn=f?{PackageType:"Image",Code:{ImageUri:t.ref("ImageUri")},...n.kind==="php"?{}:{ImageConfig:{Command:[V]}}}:{Runtime:s,Handler:V,Code:{S3Bucket:t.ref("ArtifactBucket"),S3Key:t.ref("ArtifactKey")},...Fe.length?{Layers:[...new Set(Fe)]}:{}};v[x]={Type:"AWS::Lambda::Function",DependsOn:[`${x}LogGroup`,...ge],Properties:{FunctionName:_,Architectures:[c],MemorySize:ee,Timeout:mt,Role:t.getAtt("AppRole","Arn"),Environment:{Variables:M(W)},EphemeralStorage:{Size:he},...rn,...Be!==void 0?{ReservedConcurrentExecutions:Be}:{},...Q,...Te}}}if(te("HttpFunction",d.http,i.http,"http",n.memory??1024,n.timeout??28,n.concurrency,E),te("CliFunction",d.cli,i.cli,"cli",n.cliMemory??1024,n.cliTimeout??900,void 0,n.cliTmpStorage??E),g)te("QueueFunction",d.queue,i.queue,"queue",n.queueMemory??1024,n.queueTimeout??120,void 0,n.queueTmpStorage??E);let Z=(n.provisionedConcurrency??0)>0?n.provisionedConcurrency:0,re=["HttpFunction","CliFunction",...g?["QueueFunction"]:[]];if(Z)for(let x of re)v[`${x}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:t.ref(x)}},v[`${x}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:t.ref(x),Name:"live",FunctionVersion:t.getAtt(`${x}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:Z}}};let fe=(x)=>Z?t.ref(`${x}Alias`):t.getAtt(x,"Arn"),ae=(x)=>Z?t.ref(`${x}Alias`):t.ref(x);v.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${a}-${r}`,ProtocolType:"HTTP"}},v.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:t.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:fe("HttpFunction"),PayloadFormatVersion:"2.0"}},v.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:t.ref("HttpApi"),RouteKey:"$default",Target:t.join("/",["integrations",t.ref("HttpIntegration")])}},v.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:t.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},v.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ae("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:t.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},I.HttpApiEndpoint={Description:"HTTP API endpoint",Value:t.getAtt("HttpApi","ApiEndpoint")},I.HttpApiId={Description:"HTTP API id",Value:t.ref("HttpApi")};let ue=(Array.isArray(n.domain)?n.domain:n.domain?[n.domain]:[]).filter(Boolean);if(ue.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 x=n.certificateArn;if(!x)v.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:ue[0],...ue.length>1?{SubjectAlternativeNames:ue.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:ue.map((_)=>({DomainName:_,HostedZoneId:n.hostedZoneId}))}},x=t.ref("HttpCertificate");ue.forEach((_,V)=>{let W=`HttpDomain${V}`;if(v[W]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:_,DomainNameConfigurations:[{CertificateArn:x,EndpointType:"REGIONAL"}]}},v[`HttpApiMapping${V}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:t.ref("HttpApi"),DomainName:t.ref(W),Stage:"$default"}},n.hostedZoneId)v[`HttpDomainRecord${V}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:_,Type:"A",AliasTarget:{DNSName:t.getAtt(W,"RegionalDomainName"),HostedZoneId:t.getAtt(W,"RegionalHostedZoneId")}}};I[`CustomDomain${V}`]={Description:`Custom domain ${_}`,Value:_},I[`CustomDomainTarget${V}`]={Description:`Point ${_} (CNAME/alias) at this APIGW regional domain`,Value:t.getAtt(W,"RegionalDomainName")}})}if(g)v.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${a}-${r}-dlq`,MessageRetentionPeriod:1209600}},m.forEach((x,_)=>{let V=`AppQueue${_}`,W=n.queueTimeout??120;v[V]={Type:"AWS::SQS::Queue",Properties:{QueueName:x.name,VisibilityTimeout:Math.min(43200,W*6),RedrivePolicy:{deadLetterTargetArn:t.getAtt("AppQueueDlq","Arn"),maxReceiveCount:n.queueTries??3}}};let ee=x.concurrency??n.queueConcurrency;v[`${V}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:t.getAtt(V,"Arn"),FunctionName:ae("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...ee?{ScalingConfig:{MaximumConcurrency:Math.max(2,ee)}}:{}}},I[`QueueUrl${_}`]={Description:`Queue URL: ${x.name}`,Value:t.ref(V)}});if(h)v.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${a}-${r}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:fe("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},v.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 _={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},V=(n.warmFunctions??["http"]).filter((W)=>W!=="queue"||g);for(let W of V){let ee=W.charAt(0).toUpperCase()+W.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);v[`Warmer${ee}Rule${he}`]={Type:"AWS::Events::Rule",Properties:{Name:`${a}-${r}-warmer-${W}-${he}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:Fe},(rn,lr)=>({Id:`warm-${W}-${he}-${lr}`,Arn:t.getAtt(_[W],"Arn"),Input:JSON.stringify({warmer:!0})}))}},Be+=Fe}v[`Warmer${ee}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:t.ref(_[W]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:t.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${a}-${r}-warmer-${W}-*`)}}}}if(S)v.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${a}-${r}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},I.CacheTableName={Description:"DynamoDB cache table",Value:t.ref("CacheTable")};if(C){if(v.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:P,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},v.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${a}-${r}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},v.AssetsDistribution={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,DefaultCacheBehavior:{TargetOriginId:"assets",ViewerProtocolPolicy:"redirect-to-https",Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},Origins:[{Id:"assets",DomainName:t.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:t.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...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.`);v.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:n.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:n.assetDomain,HostedZoneId:n.hostedZoneId}]}}}if(n.hostedZoneId)v.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:n.assetDomain,Type:"A",AliasTarget:{DNSName:t.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};I.AssetDomain={Description:"Custom asset CDN host",Value:n.assetDomain}}v.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:t.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:t.sub(`arn:aws:s3:::${P}/*`),Condition:{StringEquals:{"AWS:SourceArn":t.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},I.AssetsBucketName={Description:"Assets bucket",Value:t.ref("AssetsBucket")},I.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:t.getAtt("AssetsDistribution","DomainName")}}if(n.firewall?.enabled){let x=[],_=0;if(n.firewall.rateLimit)x.push({Name:"rate-limit",Priority:_++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:n.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-${r}-rate`}});let V={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let W of n.firewall.rules??[]){let ee=V[W];if(!ee)continue;x.push({Name:`managed-${W}`,Priority:_++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:ee}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-${r}-${W}`}})}v.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${a}-${r}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:x,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${a}-${r}-waf`}}},I.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.");v.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:n.vpc.id,GroupDescription:`${a}-${r} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(U)v.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${a}-${r}-efs`}]}},q.forEach((x,_)=>{v[`EfsMountTarget${_}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:t.ref("EfsFileSystem"),SubnetId:x,SecurityGroups:[t.getAtt("DataSecurityGroup","GroupId")]}}}),v.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:t.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},I.EfsFileSystemId={Description:"EFS file system id",Value:t.ref("EfsFileSystem")};if(n.cache?.driver==="elasticache")v.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${a}-${r} cache subnets`,SubnetIds:q}},v.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${a}-${r}-cache`,ReplicationGroupDescription:`${a}-${r} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:t.ref("CacheSubnetGroup"),SecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},I.CacheEndpoint={Description:"Redis primary endpoint",Value:t.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(n.database?.connection==="aurora-serverless")v.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${a}-${r} db subnets`,SubnetIds:q}},v.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${a}/${r}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},v.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${a}-${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")]}},v.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:t.ref("DbCluster")}},I.DbEndpoint={Description:"Aurora cluster endpoint",Value:t.getAtt("DbCluster","Endpoint.Address")};if(n.rdsProxy&&n.database?.connection==="aurora-serverless")v.DbProxyRole={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"read-db-secret",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:t.ref("DbSecret")}]}}]}},v.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof n.rdsProxy==="object"&&n.rdsProxy.name?n.rdsProxy.name:`${a}-${r}-proxy`,EngineFamily:"MYSQL",RoleArn:t.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:t.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:q,VpcSecurityGroupIds:[t.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},v.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:t.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[t.ref("DbCluster")]}},I.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:t.getAtt("DbProxy","Endpoint")};if(I.HttpFunctionName={Description:"HTTP function name",Value:t.ref("HttpFunction")},I.CliFunctionName={Description:"CLI function name",Value:t.ref("CliFunction")},g)I.QueueFunctionName={Description:"Queue function name",Value:t.ref("QueueFunction")};let Ee={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${e.config.project.name} (${a}-${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:v,Outputs:I},Le={};for(let x of Object.values(v))Le[x.Type]=(Le[x.Type]??0)+1;return{template:Ee,functionNames:d,queueNames:p,resourceSummary:Le}}var hp=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function yp(e){let n=`php${e.replace(".","")}`;return hp.map((r)=>`${n}-php-${r}`)}function Ja(e,n){let r=`php${e.replace(".","")}`,i=yp(e).join(" \\\n "),a=`/opt/remi/${r}/root`,s=`/etc/opt/remi/${r}`;return`${n?`FROM almalinux:9 AS ${n}`:"FROM almalinux:9"}
|
|
7252
7252
|
|
|
7253
7253
|
# Build PHP on AlmaLinux 9 (where Remi's version-isolated SCL packages install
|
|
7254
7254
|
# cleanly — Remi's release RPM rejects Amazon Linux 2023). AlmaLinux 9 shares
|
|
@@ -7309,7 +7309,7 @@ COPY app/ \${LAMBDA_TASK_ROOT}/
|
|
|
7309
7309
|
|
|
7310
7310
|
# Per-function CMD (e.g. index.http) is supplied via ImageConfig.Command.
|
|
7311
7311
|
CMD [ "index.http" ]
|
|
7312
|
-
`}import{execFileSync as ct}from"node:child_process";import{mkdtempSync as Qn,readFileSync as lt,rmSync as Jn}from"node:fs";import{tmpdir as Yn}from"node:os";import{dirname as Ss,join as pe}from"node:path";import{fileURLToPath as As}from"node:url";function Zn(){return Ss(As(import.meta.url))}function cd(){return lt(pe(Zn(),"runtime.mjs"),"utf-8")}function Xn(e){return lt(pe(Zn(),`${e}-bootstrap`),"utf-8")}function oh(e){let n=e.architecture??"x86_64",r=n==="arm64"?"arm64":"x64",i=e.version.replace(/^v/,""),a=e.onStep??(()=>{}),s=Qn(pe(Yn(),"tscloud-node-layer-"));try{let c=i.includes(".")?i:Cs(i),u=`node-v${c}-linux-${r}`,d=`https://nodejs.org/dist/v${c}/${u}.tar.xz`;a(`downloading Node ${c} (${n})`);let m=pe(s,"node.tar.xz");er(d,m),a("extracting node binary"),ct("tar",["-xf",m,"-C",s,`${u}/bin/node`],{stdio:"inherit"});let p=lt(pe(s,u,"bin","node"));a("packaging layer");let g=[{name:"bootstrap",data:Xn("node"),mode:493},{name:"runtime.mjs",data:cd(),mode:420},{name:"bin/node",data:p,mode:493}];return{zip:Dt(g),architecture:n,version:c,fileCount:g.length}}finally{Jn(s,{recursive:!0,force:!0})}}function sh(e){let n=e.architecture??"x86_64",r=n==="arm64"?"bun-linux-aarch64":"bun-linux-x64",i=e.version==="latest"?"":e.version.replace(/^v/,""),a=e.onStep??(()=>{}),s=Qn(pe(Yn(),"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`;a(`downloading Bun ${i||"latest"} (${n})`);let u=pe(s,"bun.zip");er(c,u),a("extracting bun binary"),ct("unzip",["-o","-q",u,"-d",s],{stdio:"inherit"});let d=lt(pe(s,r,"bun"));a("packaging layer");let m=[{name:"bootstrap",data:Xn("bun"),mode:493},{name:"runtime.mjs",data:cd(),mode:420},{name:"bin/bun",data:d,mode:493}];return{zip:Dt(m),architecture:n,version:i||"latest",fileCount:m.length}}finally{Jn(s,{recursive:!0,force:!0})}}function er(e,n){ct("curl",["-fsSL","-o",n,e],{stdio:["ignore","ignore","inherit"]})}function Cs(e){let n=ct("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),i=JSON.parse(n).find((a)=>a.version.startsWith(`v${e}.`));if(!i)throw Error(`No Node release found for major version ${e}`);return i.version.replace(/^v/,"")}import{AsyncLocalStorage as Ts}from"node:async_hooks";import{createHash as vs}from"node:crypto";var Qa="x-ts-cloud-invoke-depth",Ya="x-ts-cloud-invoke-chain",Za="x-ts-cloud-trace-id";function ld(e){return vs("sha256").update(e).digest("hex").slice(0,8)}var zi={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 dd(e,n=64){if(!e)return[];return e.split(".").map((r)=>r.trim()).filter((r)=>/^[0-9a-f]{8}$/.test(r)).slice(-n)}function ud(e,n=zi){let r=ld(e.functionId),i=dd(en(e.headers,Ya)),a=e.traceId??en(e.headers,Za)??crypto.randomUUID(),s=[...i,r],c=i.filter((g)=>g===r).length,u=i[i.length-1]===r,d=Number.parseInt(en(e.headers,Qa)??"",10),m=Math.max(s.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:s,traceId:a,selfInvocation:u,repeats:c,propagate:{[Qa]:String(m),[Ya]:s.join("."),[Za]:a}}}var tr={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 Yo{limits;clock;traces=new Map;breakers=new Map;constructor(e=zi,n=()=>Date.now()){this.limits=e;this.clock=n}check(e){let n=this.clock();this.expireTraces(n);let r=ud(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 a=this.traces.get(r.traceId)??{count:0,firstAt:n};if(a.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(r.traceId,a),this.deny(e.functionId,r,"trace_budget_exceeded",n,!0);if(this.traces.set(r.traceId,{count:a.count+1,firstAt:a.firstAt}),i)this.breakers.set(e.functionId,{consecutiveBlocks:0});return{...r,allowed:!0,reason:"ok",propagate:r.propagate}}deny(e,n,r,i,a){if(a){let s=this.breakers.get(e)??{consecutiveBlocks:0},c=s.consecutiveBlocks+1;this.breakers.set(e,{consecutiveBlocks:c,openUntil:c>=this.limits.breakerThreshold?i+this.limits.breakerCooldownMs:s.openUntil})}return{...n,allowed:!1,reason:r,message:tr[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 ec(e){return{...e.propagate}}function tc(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??tr[e.reason],depth:e.depth,traceId:e.traceId}}}var pd=new Ts;function nr(e){let n=globalThis.process?.env?.[e];if(n==null||n==="")return;return n!=="0"&&n.toLowerCase()!=="false"}function Rs(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function bp(e){let n=e===!1?{enabled:!1}:e??{},r=nr("TS_CLOUD_RECURSION_PROTECTION"),i=nr("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:r??n.enabled??!0,detectionOnly:i??n.detectionOnly??!1,limits:{...zi,...n.limits},functionId:n.functionId??Rs()}}var ve,oe;function Sp(){let e=globalThis.fetch;if(!e||ve===e)return()=>{};oe=e;let n=async(r,i)=>{let a=pd.getStore();if(!a)return oe(r,i);let s=new Headers(i?.headers??(r instanceof Request?r.headers:void 0));for(let[c,u]of Object.entries(ec(a)))s.set(c,u);if(r instanceof Request)return oe(new Request(r,{headers:s}),i);return oe(r,{...i,headers:s})};return Object.assign(n,e),globalThis.fetch=n,ve=n,()=>{if(globalThis.fetch===ve&&oe)globalThis.fetch=oe;ve=void 0}}var ut,tn;function vp(e){if(!ut||JSON.stringify(tn)!==JSON.stringify(e))ut=new Yo(e),tn=e;return ut}function ah(){if(ut=void 0,tn=void 0,ve&&oe&&globalThis.fetch===ve)globalThis.fetch=oe;ve=void 0,oe=void 0}function md(e,n){let r=bp(n);if(!r.enabled)return;let i=vp(r.limits),a={functionId:r.functionId,headers:e},s=i.check(a);return{verdict:s,blocked:!s.allowed&&!r.detectionOnly,observed:!s.allowed&&r.detectionOnly}}function gd(e,n){return Sp(),pd.run(e,n)}function ch(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 Ps=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function Es(e){if(!e)return!0;return Ps.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 Cp(e){let n=e.requestContext?.domainName??"localhost",r=e.rawQueryString?`?${e.rawQueryString}`:"",i=`https://${n}${e.rawPath||"/"}${r}`,a=new Headers;for(let[u,d]of Object.entries(e.headers??{}))if(d!==void 0)a.set(u,d);if(e.cookies?.length)a.set("cookie",e.cookies.join("; "));let s=e.requestContext.http.method,c;if(e.body!==void 0&&s!=="GET"&&s!=="HEAD")c=e.isBase64Encoded?new Uint8Array(Buffer.from(e.body,"base64")):new TextEncoder().encode(e.body);return new Request(i,{method:s,headers:a,body:c})}async function fd(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 a=Buffer.from(await e.arrayBuffer()),s=Es(e.headers.get("content-type"));return{statusCode:e.status,headers:n,...r.length?{cookies:r}:{},body:s?a.toString("utf-8"):a.toString("base64"),isBase64Encoded:!s}}function Tp(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 a=md(r.headers??{},n?.recursionProtection);if(a?.blocked){let c=tc(a.verdict);return{statusCode:c.status,headers:{...c.headers,"retry-after":"60"},body:JSON.stringify(c.body),isBase64Encoded:!1}}let s=Cp(r);if(!a){let c=await e(s);return fd(c)}if(a.observed)console.warn(`[ts-cloud] recursion detected (${a.verdict.reason}) at depth ${a.verdict.depth}; detection-only mode let it run`);return gd(a.verdict,async()=>fd(await e(s)))}}function Is(e){try{return JSON.parse(e)}catch{return e}}function Ep(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(Is(i.body),i)}catch{r.push({itemIdentifier:i.messageId})}return{batchItemFailures:r}}}function wp(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 lh(e,n){return{http:Tp(e.fetch,n),queue:Ep(e.queue),cli:wp(e.cli)}}function hd(e={}){let n=e.socketPath??"/tmp/.tscloud-fpm.sock",r=e.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
|
|
7312
|
+
`}import{execFileSync as ct}from"node:child_process";import{mkdtempSync as Qn,readFileSync as lt,rmSync as Jn}from"node:fs";import{tmpdir as Yn}from"node:os";import{dirname as vs,join as pe}from"node:path";import{fileURLToPath as Ts}from"node:url";function Zn(){return vs(Ts(import.meta.url))}function cd(){return lt(pe(Zn(),"runtime.mjs"),"utf-8")}function Xn(e){return lt(pe(Zn(),`${e}-bootstrap`),"utf-8")}function oh(e){let n=e.architecture??"x86_64",r=n==="arm64"?"arm64":"x64",i=e.version.replace(/^v/,""),a=e.onStep??(()=>{}),s=Qn(pe(Yn(),"tscloud-node-layer-"));try{let c=i.includes(".")?i:Rs(i),u=`node-v${c}-linux-${r}`,d=`https://nodejs.org/dist/v${c}/${u}.tar.xz`;a(`downloading Node ${c} (${n})`);let m=pe(s,"node.tar.xz");er(d,m),a("extracting node binary"),ct("tar",["-xf",m,"-C",s,`${u}/bin/node`],{stdio:"inherit"});let p=lt(pe(s,u,"bin","node"));a("packaging layer");let g=[{name:"bootstrap",data:Xn("node"),mode:493},{name:"runtime.mjs",data:cd(),mode:420},{name:"bin/node",data:p,mode:493}];return{zip:Dt(g),architecture:n,version:c,fileCount:g.length}}finally{Jn(s,{recursive:!0,force:!0})}}function sh(e){let n=e.architecture??"x86_64",r=n==="arm64"?"bun-linux-aarch64":"bun-linux-x64",i=e.version==="latest"?"":e.version.replace(/^v/,""),a=e.onStep??(()=>{}),s=Qn(pe(Yn(),"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`;a(`downloading Bun ${i||"latest"} (${n})`);let u=pe(s,"bun.zip");er(c,u),a("extracting bun binary"),ct("unzip",["-o","-q",u,"-d",s],{stdio:"inherit"});let d=lt(pe(s,r,"bun"));a("packaging layer");let m=[{name:"bootstrap",data:Xn("bun"),mode:493},{name:"runtime.mjs",data:cd(),mode:420},{name:"bin/bun",data:d,mode:493}];return{zip:Dt(m),architecture:n,version:i||"latest",fileCount:m.length}}finally{Jn(s,{recursive:!0,force:!0})}}function er(e,n){ct("curl",["-fsSL","-o",n,e],{stdio:["ignore","ignore","inherit"]})}function Rs(e){let n=ct("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),i=JSON.parse(n).find((a)=>a.version.startsWith(`v${e}.`));if(!i)throw Error(`No Node release found for major version ${e}`);return i.version.replace(/^v/,"")}import{AsyncLocalStorage as Es}from"node:async_hooks";import{createHash as Ps}from"node:crypto";var Qa="x-ts-cloud-invoke-depth",Ya="x-ts-cloud-invoke-chain",Za="x-ts-cloud-trace-id";function ld(e){return Ps("sha256").update(e).digest("hex").slice(0,8)}var Gi={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 dd(e,n=64){if(!e)return[];return e.split(".").map((r)=>r.trim()).filter((r)=>/^[0-9a-f]{8}$/.test(r)).slice(-n)}function ud(e,n=Gi){let r=ld(e.functionId),i=dd(en(e.headers,Ya)),a=e.traceId??en(e.headers,Za)??crypto.randomUUID(),s=[...i,r],c=i.filter((g)=>g===r).length,u=i[i.length-1]===r,d=Number.parseInt(en(e.headers,Qa)??"",10),m=Math.max(s.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:s,traceId:a,selfInvocation:u,repeats:c,propagate:{[Qa]:String(m),[Ya]:s.join("."),[Za]:a}}}var tr={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 ts{limits;clock;traces=new Map;breakers=new Map;constructor(e=Gi,n=()=>Date.now()){this.limits=e;this.clock=n}check(e){let n=this.clock();this.expireTraces(n);let r=ud(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 a=this.traces.get(r.traceId)??{count:0,firstAt:n};if(a.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(r.traceId,a),this.deny(e.functionId,r,"trace_budget_exceeded",n,!0);if(this.traces.set(r.traceId,{count:a.count+1,firstAt:a.firstAt}),i)this.breakers.set(e.functionId,{consecutiveBlocks:0});return{...r,allowed:!0,reason:"ok",propagate:r.propagate}}deny(e,n,r,i,a){if(a){let s=this.breakers.get(e)??{consecutiveBlocks:0},c=s.consecutiveBlocks+1;this.breakers.set(e,{consecutiveBlocks:c,openUntil:c>=this.limits.breakerThreshold?i+this.limits.breakerCooldownMs:s.openUntil})}return{...n,allowed:!1,reason:r,message:tr[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 ec(e){return{...e.propagate}}function tc(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??tr[e.reason],depth:e.depth,traceId:e.traceId}}}var pd=new Es;function nr(e){let n=globalThis.process?.env?.[e];if(n==null||n==="")return;return n!=="0"&&n.toLowerCase()!=="false"}function ws(){let e=globalThis.process?.env??{};return e.TS_CLOUD_FUNCTION_ID||e.AWS_LAMBDA_FUNCTION_NAME||e.FUNCTION_NAME||"function"}function bp(e){let n=e===!1?{enabled:!1}:e??{},r=nr("TS_CLOUD_RECURSION_PROTECTION"),i=nr("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:r??n.enabled??!0,detectionOnly:i??n.detectionOnly??!1,limits:{...Gi,...n.limits},functionId:n.functionId??ws()}}var ve,oe;function Sp(){let e=globalThis.fetch;if(!e||ve===e)return()=>{};oe=e;let n=async(r,i)=>{let a=pd.getStore();if(!a)return oe(r,i);let s=new Headers(i?.headers??(r instanceof Request?r.headers:void 0));for(let[c,u]of Object.entries(ec(a)))s.set(c,u);if(r instanceof Request)return oe(new Request(r,{headers:s}),i);return oe(r,{...i,headers:s})};return Object.assign(n,e),globalThis.fetch=n,ve=n,()=>{if(globalThis.fetch===ve&&oe)globalThis.fetch=oe;ve=void 0}}var ut,tn;function vp(e){if(!ut||JSON.stringify(tn)!==JSON.stringify(e))ut=new ts(e),tn=e;return ut}function ah(){if(ut=void 0,tn=void 0,ve&&oe&&globalThis.fetch===ve)globalThis.fetch=oe;ve=void 0,oe=void 0}function md(e,n){let r=bp(n);if(!r.enabled)return;let i=vp(r.limits),a={functionId:r.functionId,headers:e},s=i.check(a);return{verdict:s,blocked:!s.allowed&&!r.detectionOnly,observed:!s.allowed&&r.detectionOnly}}function gd(e,n){return Sp(),pd.run(e,n)}function ch(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 Is=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function Ds(e){if(!e)return!0;return Is.test(e)}function Ns(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 Cp(e){let n=e.requestContext?.domainName??"localhost",r=e.rawQueryString?`?${e.rawQueryString}`:"",i=`https://${n}${e.rawPath||"/"}${r}`,a=new Headers;for(let[u,d]of Object.entries(e.headers??{}))if(d!==void 0)a.set(u,d);if(e.cookies?.length)a.set("cookie",e.cookies.join("; "));let s=e.requestContext.http.method,c;if(e.body!==void 0&&s!=="GET"&&s!=="HEAD")c=e.isBase64Encoded?new Uint8Array(Buffer.from(e.body,"base64")):new TextEncoder().encode(e.body);return new Request(i,{method:s,headers:a,body:c})}async function fd(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 a=Buffer.from(await e.arrayBuffer()),s=Ds(e.headers.get("content-type"));return{statusCode:e.status,headers:n,...r.length?{cookies:r}:{},body:s?a.toString("utf-8"):a.toString("base64"),isBase64Encoded:!s}}function Tp(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=Ns(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 a=md(r.headers??{},n?.recursionProtection);if(a?.blocked){let c=tc(a.verdict);return{statusCode:c.status,headers:{...c.headers,"retry-after":"60"},body:JSON.stringify(c.body),isBase64Encoded:!1}}let s=Cp(r);if(!a){let c=await e(s);return fd(c)}if(a.observed)console.warn(`[ts-cloud] recursion detected (${a.verdict.reason}) at depth ${a.verdict.depth}; detection-only mode let it run`);return gd(a.verdict,async()=>fd(await e(s)))}}function xs(e){try{return JSON.parse(e)}catch{return e}}function Ep(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(xs(i.body),i)}catch{r.push({itemIdentifier:i.messageId})}return{batchItemFailures:r}}}function wp(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 lh(e,n){return{http:Tp(e.fetch,n),queue:Ep(e.queue),cli:wp(e.cli)}}function hd(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
7313
|
[global]
|
|
7314
7314
|
daemonize = no
|
|
7315
7315
|
error_log = ${e.errorLog??"/tmp/storage/logs/php-fpm.log"}
|
|
@@ -7326,4 +7326,4 @@ decorate_workers_output = no
|
|
|
7326
7326
|
php_admin_value[error_log] = /dev/stderr
|
|
7327
7327
|
php_admin_flag[log_errors] = on
|
|
7328
7328
|
clear_env = no
|
|
7329
|
-
`}import{readFileSync as Ds}from"node:fs";import{dirname as Ns,join as rr}from"node:path";import{fileURLToPath as xs}from"node:url";function ks(){return rr(Ns(xs(import.meta.url)),"runtime-assets")}function In(){let e=ks(),n=(r)=>Ds(rr(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:hd(),mode:420}]}function rc(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 yd=["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 Ms,mkdirSync as Ls,mkdtempSync as Os,readdirSync as $s,readFileSync as Bs,rmSync as Fs,statSync as ir,writeFileSync as Gs}from"node:fs";import{tmpdir as _s}from"node:os";import{join as Me,relative as Ws}from"node:path";function*ar(e){for(let n of $s(e)){let r=Me(e,n);if(ir(r).isDirectory())yield*ar(r);else yield r}}function dh(e={}){let n=e.architecture??"x86_64",r=e.platform??(n==="arm64"?"linux/arm64":"linux/amd64"),i=e.onStep??(()=>{}),a=Os(Me(_s(),"tscloud-php-layer-")),s="tscloud-php-layer:build";try{Gs(Me(a,"Dockerfile"),ad(e)),i("Building PHP runtime image (docker)"),dt("docker",["build","--platform",r,"-t","tscloud-php-layer:build",a],{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(a,"opt");Ls(u,{recursive:!0});try{dt("docker",["cp",`${c}:/opt/php`,Me(u,"php")],{stdio:"inherit"})}finally{dt("docker",["rm",c],{stdio:"ignore"})}if(!Ms(Me(u,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let d=[];for(let y of ar(u)){let f=Ws(u,y).replace(/\\/g,"/"),h=ir(y).mode&73?493:420;d.push({name:f,data:Bs(y),mode:h})}i("Injecting runtime assets");let m=new Set(In().map((y)=>y.path)),p=d.filter((y)=>!m.has(y.name));for(let y of In())p.push({name:y.path,data:y.contents,mode:y.mode});return i("Packaging layer ZIP"),{zip:Dt(p),architecture:n,fileCount:p.length}}finally{Fs(a,{recursive:!0,force:!0})}}import{execSync as Vs}from"node:child_process";import{createHash as Us}from"node:crypto";import{readdirSync as Hs,readFileSync as js,statSync as sr}from"node:fs";import{join as Ks,relative as or,resolve as nn}from"node:path";var Ap=[".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 qs(e,n){return n.some((r)=>e===r||e.startsWith(`${r}/`))}function*cr(e,n,r){for(let i of Hs(e)){let a=Ks(e,i),s=or(n,a).replace(/\\/g,"/");if(qs(s,r))continue;if(sr(a).isDirectory())yield*cr(a,n,r);else yield a}}function Zo(e){if(e.skipBuild)return;let n=nn(e.projectRoot??process.cwd()),r=e.app.build??yd;for(let i of r)e.onStep?.(`build: ${i}`),Vs(i,{stdio:"inherit",cwd:n})}function es(e,n=[]){let r=nn(e),i=[...Ap,vn(),...n],a=[];for(let s of cr(r,r,i)){let c=or(r,s).replace(/\\/g,"/"),u=(sr(s).mode&73)!==0;a.push({name:c,data:js(s),mode:u?493:420})}return a}function nc(e){let n=nn(e.projectRoot??process.cwd());Zo(e),e.onStep?.("packaging application tree");let r=es(n,e.exclude);if(!r.length)throw Error(`No files to package under ${n}`);let i=Dt(r),a=e.app.handlers?.http??"public/index.php";return{zip:i,sha256:Us("sha256").update(i).digest("hex"),handlers:{http:a,queue:e.app.handlers?.queue??a,cli:e.app.handlers?.cli??a},fileCount:r.length}}class bd{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 uh=new bd;class ic{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++}`,a={id:i,sourceRegion:e,destRegion:n,destBucket:r};return this.replicationRules.set(i,a),a}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 Rp=new ic;class Sd{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,n=30,r=10){let i=`health-${Date.now()}-${this.counter++}`,a={id:i,url:e,interval:n,timeout:r,status:"healthy"};return this.checks.set(i,a),a}createSyntheticMonitor(e,n,r,i){let a=`synthetic-${Date.now()}-${this.counter++}`,s={id:a,name:e,script:n,frequency:r,locations:i};return this.synthetics.set(a,s),s}trackUptime(e,n,r){let i=`uptime-${Date.now()}-${this.counter++}`,a=n/(n+r)*100,s={id:i,resource:e,uptime:n,downtime:r,availability:a};return this.uptimeTrackers.set(i,s),s}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var ph=new Sd;class vd{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,n,r,i){let a=`waf-${Date.now()}-${this.counter++}`,s={id:a,name:e,priority:n,action:r,conditions:i};return this.wafRules.set(a,s),s}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++}`,a={id:i,name:e,vpcId:n,rules:r};return this.securityGroups.set(i,a),a}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 mh=new vd;class Cd{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++}`,a={id:i,name:e,query:{resourceTypeFilters:n,tagFilters:r}};return this.groups.set(i,a),a}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var gh=new Cd;export{hm,ym,sa,Zc,aa,ca,vn,je,A,la,el,H,Mr,w,eu,ne,Ur,da,Vo,le,B,zo,tu,ru,nu,iu,l,o,bm,Sm,T,ua,pa,ma,vm,Cm,Oe,ga,_i,ou,Tm,Em,Ve,At,fa,tl,rl,wm,nl,il,ol,Ho,ha,nt,qo,Cn,Oi,Tn,ze,su,Go,Wo,ya,ba,Sa,va,Ca,Ta,Ae,j,au,cu,sl,b,L,it,k,al,Rt,ye,Gt,Am,cl,Re,Ko,He,Wt,$i,Ie,Jo,$e,lu,Li,Pe,De,ie,Mi,X,Kt,It,ke,t,En,Rm,ll,Ea,Im,Pm,Dm,km,wa,Nm,xm,_m,Om,$m,Lm,Mm,Um,Fm,Bm,jm,Vm,du,uu,pu,mu,gu,fu,hu,Jt,dl,ul,Fr,Ui,zm,pl,Hm,qm,wn,Gm,Wm,Km,Jm,Xm,Qm,yu,bu,Su,vu,Cu,Fi,Ym,An,Tu,ml,Eu,Aa,be,wu,Au,Pt,Xo,Xt,Ru,gl,Iu,Pu,Du,fl,Se,Zm,eg,tg,rg,ku,ng,Ne,ig,og,sg,Ra,Ia,Nu,hl,yl,ag,cg,lg,dg,ug,xu,Pa,pg,mg,gg,fg,hg,_u,Ou,yg,bg,Sg,vg,Cg,Tg,Eg,$u,wg,bl,Da,Ag,Rg,Ig,Pg,Sl,vl,Cl,Dg,ka,Lu,Mu,Uu,Fu,Na,Bu,kg,Ng,xg,_g,Og,$g,Lg,ju,Vu,zu,Hu,Tl,Mg,Ug,Fg,Bg,jg,Vg,zg,Hg,qg,qu,Gu,Wu,Ku,Gg,Wg,El,Kg,wl,Al,Rl,Il,Jg,Xg,Qg,Yg,ot,Bi,Zg,ef,tf,rf,nf,of,sf,af,Ju,cf,lf,Pl,Dl,df,uf,Xu,pf,mf,gf,ff,hf,yf,bf,Sf,vf,Cf,Tf,Ef,wf,Af,Rf,If,Pf,Df,kf,Nf,xf,xa,Qu,_a,Yu,Oa,Zu,$a,ep,La,tp,Br,rp,Ma,np,ji,ip,Ua,op,Fa,sp,kl,_f,Nl,Of,Ba,ap,jr,cp,xl,$f,ja,lp,_l,Lf,Ol,Mf,$l,Uf,Va,dp,Ll,Ff,Ml,Bf,Ul,jf,Fl,Vf,za,up,Ha,pp,Bl,zf,jl,Hf,Vl,qf,zl,Gf,Hl,Wf,ql,Kf,qa,mp,Gl,Jf,Wl,Xf,Kl,Qf,Jl,Yf,Xl,Zf,Ql,eh,Yl,Zl,ed,td,rd,th,nd,rh,id,nh,od,ih,Dt,sd,gp,Qo,Ga,Rn,fp,Vi,Qt,Wa,Ka,hp,yp,Ja,ad,Xa,cd,oh,sh,Qa,Ya,Za,ld,zi,dd,ud,Yo,ec,tc,pd,bp,Sp,vp,ah,md,gd,ch,Cp,fd,Tp,Ep,wp,lh,hd,In,rc,yd,dh,Ap,Zo,es,nc,bd,uh,ic,Rp,Sd,ph,vd,mh,Cd,gh};
|
|
7329
|
+
`}import{readFileSync as ks}from"node:fs";import{dirname as Ms,join as rr}from"node:path";import{fileURLToPath as Ls}from"node:url";function Os(){return rr(Ms(Ls(import.meta.url)),"runtime-assets")}function Pn(){let e=Os(),n=(r)=>ks(rr(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:hd(),mode:420}]}function rc(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 yd=["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 $s,mkdirSync as Bs,mkdtempSync as Fs,readdirSync as Gs,readFileSync as _s,rmSync as Ws,statSync as ir,writeFileSync as Vs}from"node:fs";import{tmpdir as Us}from"node:os";import{join as Me,relative as Hs}from"node:path";function*ar(e){for(let n of Gs(e)){let r=Me(e,n);if(ir(r).isDirectory())yield*ar(r);else yield r}}function dh(e={}){let n=e.architecture??"x86_64",r=e.platform??(n==="arm64"?"linux/arm64":"linux/amd64"),i=e.onStep??(()=>{}),a=Fs(Me(Us(),"tscloud-php-layer-")),s="tscloud-php-layer:build";try{Vs(Me(a,"Dockerfile"),ad(e)),i("Building PHP runtime image (docker)"),dt("docker",["build","--platform",r,"-t","tscloud-php-layer:build",a],{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(a,"opt");Bs(u,{recursive:!0});try{dt("docker",["cp",`${c}:/opt/php`,Me(u,"php")],{stdio:"inherit"})}finally{dt("docker",["rm",c],{stdio:"ignore"})}if(!$s(Me(u,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let d=[];for(let y of ar(u)){let f=Hs(u,y).replace(/\\/g,"/"),h=ir(y).mode&73?493:420;d.push({name:f,data:_s(y),mode:h})}i("Injecting runtime assets");let m=new Set(Pn().map((y)=>y.path)),p=d.filter((y)=>!m.has(y.name));for(let y of Pn())p.push({name:y.path,data:y.contents,mode:y.mode});return i("Packaging layer ZIP"),{zip:Dt(p),architecture:n,fileCount:p.length}}finally{Ws(a,{recursive:!0,force:!0})}}import{execSync as js}from"node:child_process";import{createHash as Ks}from"node:crypto";import{readdirSync as qs,readFileSync as zs,statSync as sr}from"node:fs";import{join as Qs,relative as or,resolve as nn}from"node:path";var Ap=[".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 Js(e,n){return n.some((r)=>e===r||e.startsWith(`${r}/`))}function*cr(e,n,r){for(let i of qs(e)){let a=Qs(e,i),s=or(n,a).replace(/\\/g,"/");if(Js(s,r))continue;if(sr(a).isDirectory())yield*cr(a,n,r);else yield a}}function rs(e){if(e.skipBuild)return;let n=nn(e.projectRoot??process.cwd()),r=e.app.build??yd;for(let i of r)e.onStep?.(`build: ${i}`),js(i,{stdio:"inherit",cwd:n})}function ns(e,n=[]){let r=nn(e),i=[...Ap,Cn(),...n],a=[];for(let s of cr(r,r,i)){let c=or(r,s).replace(/\\/g,"/"),u=(sr(s).mode&73)!==0;a.push({name:c,data:zs(s),mode:u?493:420})}return a}function nc(e){let n=nn(e.projectRoot??process.cwd());rs(e),e.onStep?.("packaging application tree");let r=ns(n,e.exclude);if(!r.length)throw Error(`No files to package under ${n}`);let i=Dt(r),a=e.app.handlers?.http??"public/index.php";return{zip:i,sha256:Ks("sha256").update(i).digest("hex"),handlers:{http:a,queue:e.app.handlers?.queue??a,cli:e.app.handlers?.cli??a},fileCount:r.length}}class bd{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 uh=new bd;class ic{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++}`,a={id:i,sourceRegion:e,destRegion:n,destBucket:r};return this.replicationRules.set(i,a),a}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 Rp=new ic;class Sd{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(e,n=30,r=10){let i=`health-${Date.now()}-${this.counter++}`,a={id:i,url:e,interval:n,timeout:r,status:"healthy"};return this.checks.set(i,a),a}createSyntheticMonitor(e,n,r,i){let a=`synthetic-${Date.now()}-${this.counter++}`,s={id:a,name:e,script:n,frequency:r,locations:i};return this.synthetics.set(a,s),s}trackUptime(e,n,r){let i=`uptime-${Date.now()}-${this.counter++}`,a=n/(n+r)*100,s={id:i,resource:e,uptime:n,downtime:r,availability:a};return this.uptimeTrackers.set(i,s),s}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var ph=new Sd;class vd{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(e,n,r,i){let a=`waf-${Date.now()}-${this.counter++}`,s={id:a,name:e,priority:n,action:r,conditions:i};return this.wafRules.set(a,s),s}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++}`,a={id:i,name:e,vpcId:n,rules:r};return this.securityGroups.set(i,a),a}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 mh=new vd;class Cd{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++}`,a={id:i,name:e,query:{resourceTypeFilters:n,tagFilters:r}};return this.groups.set(i,a),a}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var gh=new Cd;export{hm,ym,sa,Zc,aa,ca,Cn,je,A,la,el,H,Ur,w,eu,ne,Fr,da,qo,le,B,Go,tu,ru,nu,iu,l,o,bm,Sm,T,ua,pa,ma,vm,Cm,Oe,ga,Li,ou,Tm,Em,Ve,At,fa,tl,rl,wm,nl,il,ol,Wo,ha,it,Ko,Tn,Mi,En,ze,su,Jo,Xo,ya,ba,Sa,va,Ca,Ta,Ae,j,au,cu,sl,b,L,ot,k,al,Rt,ye,Gt,Am,cl,Re,Qo,He,Wt,Ui,Ie,Yo,$e,lu,Fi,Pe,De,ie,Bi,X,Kt,It,ke,t,wn,Rm,ll,Ea,Im,Pm,Dm,km,wa,Nm,xm,_m,Om,$m,Lm,Mm,Um,Fm,Bm,jm,Vm,du,uu,pu,mu,gu,fu,hu,Jt,dl,ul,Br,ji,zm,pl,Hm,qm,An,Gm,Wm,Km,Jm,Xm,Qm,yu,bu,Su,vu,Cu,Vi,Ym,Rn,Tu,ml,Eu,Aa,be,wu,Au,Pt,Zo,Xt,Ru,gl,Iu,Pu,Du,fl,Se,Zm,eg,tg,rg,ku,ng,Ne,ig,og,sg,Ra,Ia,Nu,hl,yl,ag,cg,lg,dg,ug,xu,Pa,pg,mg,gg,fg,hg,_u,Ou,yg,bg,Sg,vg,Cg,Tg,Eg,$u,wg,bl,Da,Ag,Rg,Ig,Pg,Sl,vl,Cl,Dg,ka,Lu,Mu,Uu,Fu,Na,Bu,kg,Ng,xg,_g,Og,$g,Lg,ju,Vu,zu,Hu,Tl,Mg,Ug,Fg,Bg,jg,Vg,zg,Hg,qg,qu,Gu,Wu,Ku,Gg,Wg,El,Kg,wl,Al,Rl,Il,Jg,Xg,Qg,Yg,st,zi,Zg,ef,tf,rf,nf,of,sf,af,Ju,cf,lf,Pl,Dl,df,uf,Xu,pf,mf,gf,ff,hf,yf,bf,Sf,vf,Cf,Tf,Ef,wf,Af,Rf,If,Pf,Df,kf,Nf,xf,xa,Qu,_a,Yu,Oa,Zu,$a,ep,La,tp,jr,rp,Ma,np,Hi,ip,Ua,op,Fa,sp,kl,_f,Nl,Of,Ba,ap,Vr,cp,xl,$f,ja,lp,_l,Lf,Ol,Mf,$l,Uf,Va,dp,Ll,Ff,Ml,Bf,Ul,jf,Fl,Vf,za,up,Ha,pp,Bl,zf,jl,Hf,Vl,qf,zl,Gf,Hl,Wf,ql,Kf,qa,mp,Gl,Jf,Wl,Xf,Kl,Qf,Jl,Yf,Xl,Zf,Ql,eh,Yl,Zl,ed,td,rd,th,nd,rh,id,nh,od,ih,Dt,sd,gp,es,Ga,In,fp,qi,Qt,Wa,Ka,hp,yp,Ja,ad,Xa,cd,oh,sh,Qa,Ya,Za,ld,Gi,dd,ud,ts,ec,tc,pd,bp,Sp,vp,ah,md,gd,ch,Cp,fd,Tp,Ep,wp,lh,hd,Pn,rc,yd,dh,Ap,rs,ns,nc,bd,uh,ic,Rp,Sd,ph,vd,mh,Cd,gh};
|